[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\"@babel/preset-env\"]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# @see: https://editorconfig.org/\nroot = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ncharset = utf-8\nindent_style = space\nindent_size = 2\ntrim_trailing_whitespace = true\nquote_type = single\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"root\": true,\n  \"extends\": \"airbnb\",\n  \"plugins\": [\"jest\"],\n  \"env\": {\n    \"jest/globals\": true\n  },\n  \"rules\": {\n    \"no-bitwise\": \"off\",\n    \"no-lonely-if\": \"off\",\n    \"class-methods-use-this\": \"off\",\n    \"arrow-body-style\": \"off\",\n    \"no-loop-func\": \"off\"\n  },\n  \"ignorePatterns\": [\"*.md\", \"*.png\", \"*.jpeg\", \"*.jpg\"],\n  \"settings\": {\n    \"react\": {\n      \"version\": \"18.2.0\"\n    }\n  }\n}\n"
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [ 22.x ]\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n\n      - name: Setup Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n\n      - name: Install dependencies\n        run: npm i\n\n      - name: Run linting\n        run: npm run lint\n\n      - name: Run tests\n        run: npm run coverage\n\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v4\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.idea\ncoverage\n.vscode\n.DS_Store\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "npm run lint\n"
  },
  {
    "path": ".npmrc",
    "content": "engine-strict=true\n"
  },
  {
    "path": ".nvmrc",
    "content": "v22\n"
  },
  {
    "path": "BACKERS.md",
    "content": "# Project Backers\n\n> You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n## `O(2ⁿ)` Backers\n\n`null`\n\n## `O(n²)` Backers\n\n`null`\n\n## `O(n×log(n))` Backers\n\n`null`\n\n<!--\n<table>\n  <tr>\n    <td align=\"center\">\n      <a href=\"[PROFILE_URL]\">\n        <img\n          src=\"[PROFILE_IMG_SRC]\"\n          width=\"50\"\n          height=\"50\"\n        />\n      </a>\n      <br />\n      <a href=\"[PROFILE_URL]\">[PROFILE_NAME]</a>\n    </td>\n  </tr>\n</table>\n-->\n\n<!--\n<ul>\n  <li>\n    <a href=\"[PROFILE_URL]\">\n      <img\n        src=\"[PROFILE_IMG_SRC]\"\n        width=\"30\"\n        height=\"30\"\n      /></a>\n    &thinsp;\n    <a href=\"[PROFILE_URL]\">[PROFILE_NAME]</a>\n  </li>\n</ul>\n-->\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Contributing\n\n**General Rules**\n\n- As much as possible, try to follow the existing format of markdown and code.\n- Don't forget to run `npm run lint` and `npm test` before submitting pull requests.\n- Make sure that **100%** of your code is covered by tests.\n\n**Contributing New Translation**\n\n- Create new `README.xx-XX.md` file with translation alongside with \nmain `README.md` file where `xx-XX` is [locale and country/region codes](http://www.lingoes.net/en/translator/langcode.htm).\nFor example `en-US`, `zh-CN`, `zh-TW`, `ko-KR` etc.\n- You may also translate all other sub-folders by creating \nrelated `README.xx-XX.md` files in each of them.\n\n**Contributing New Algorithms**\n\n- Make your pull requests to be **specific** and **focused**. Instead of \ncontributing \"several sorting algorithms\" all at once contribute them all \none by one separately (i.e. one pull request for \"Quick Sort\", another one\nfor \"Heap Sort\" and so on).\n- Provide **README.md** for each of the algorithms **with explanations** of\nthe algorithm and **with links** to further readings.\n- Describe what you do in code using **comments**.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 Oleksii Trekhleb\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.ar-AR.md",
    "content": "# جافا سكريبت خوارزميات  وهياكل البيانات\n\n[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nتحتوي هذه المقالة على أمثلة عديدة تستند إلى الخوارزميات الشائعة وهياكل البيانات في الجافا سكريبت.\n\nكل خوارزمية وهياكل البيانات لها برنامج README منفصل خاص بها\nمع التفسيرات والروابط ذات الصلة لمزيد من القراءة (بما في ذلك تلك\nإلى مقاطع فيديو YouTube).\n\n\n_اقرأ هذا في لغات أخرى:_\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## هياكل البيانات\n\nهياكل البيانات هي طريقة خاصة لتنظيم البيانات وتخزينها في جهاز الكمبيوتر بحيث\nيمكن الوصول إليها وتعديلها بكفاءة. بتعبير أدق ، هيكل البيانات هو مجموعة من البيانات\nالقيم والعلاقات فيما بينها والوظائف أو العمليات التي يمكن تطبيقها عليها\nالبيانات.\n\n\n`B` - مبتدئ, `A` - المتقدمة\n\n* `B` [قائمة مرتبطة](src/data-structures/linked-list)\n* `B` [قائمة مرتبطة بشكل مضاعف](src/data-structures/doubly-linked-list)\n* `B` [طابور, Queue](src/data-structures/queue)\n* `B` [كومة](src/data-structures/stack)\n* `B` [جدول التجزئة](src/data-structures/hash-table)\n* `B` [كومة](src/data-structures/heap) -الحد الأقصى والحد الأدنى من إصدارات الكومة\n* `B` [طابور الأولوية](src/data-structures/priority-queue)\n* `A` [تري](src/data-structures/trie)\n* `A` [شجرة](src/data-structures/tree)\n  * `A` [شجرة البحث الثنائية](src/data-structures/tree/binary-search-tree)\n  * `A` [شجرة AVL](src/data-structures/tree/avl-tree)\n  * `A` [شجرة الأحمر والأسود](src/data-structures/tree/red-black-tree)\n  * `A` [شجرة القطعة](src/data-structures/tree/segment-tree) - مع أمثلة على استفسارات النطاق الأدنى / الأقصى / المجموع\n  * `A` [شجرة فينويك](src/data-structures/tree/fenwick-tree) (شجرة ثنائية مفهرسة)\n* `A` [Graph](src/data-structures/graph) (كلاهما موجه وغير موجه)\n* `A` [مجموعة منفصلة](src/data-structures/disjoint-set)\n* `A` [مرشح بلوم](src/data-structures/bloom-filter)\n\n\n## الخوارزميات\n\nالخوارزمية هي تحديد لا لبس فيه لكيفية حل فئة من المشاكل. أنه\nمجموعة من القواعد التي تحدد بدقة تسلسل العمليات.\n\n`B` - مبتدئ ، `A` - متقدم\n\n\n### الخوارزميات حسب الموضوع\n\n* **رياضيات**\n  * `B` [معالجة البت](src/algorithms/math/bits)\n  * `B` [عاملي](src/algorithms/math/factorial)\n  * `B` [رقم فيبوناتشي](src/algorithms/math/fibonacci) - الإصدارات الكلاسيكية والمغلقة\n  * `B` [اختبار البدائية](src/algorithms/math/primality-test) (طريقة تقسيم المحاكمة)\n  * `B` [الخوارزمية الإقليدية](src/algorithms/math/euclidean-algorithm) - احسب القاسم المشترك الأكبر (GCD)\n  * `B` [أقل مضاعف مشترك](src/algorithms/math/least-common-multiple) (LCM)\n  * `B` [منخل إراتوستينس](src/algorithms/math/sieve-of-eratosthenes) - إيجاد جميع الأعداد الأولية حتى أي حد معين\n  * `B` [هي قوة اثنين](src/algorithms/math/is-power-of-two) - تحقق مما إذا كان الرقم هو قوة اثنين (الخوارزميات الساذجة والبتية)\n  * `B` [مثلث باسكال](src/algorithms/math/pascal-triangle)\n  * `B` [عدد مركب](src/algorithms/math/complex-number) - الأعداد المركبة والعمليات الأساسية معهم\n  * `B` [راديان ودرجة](src/algorithms/math/radian) - راديان لدرجة التحويل والعكس\n  * `B` [تشغيل سريع](src/algorithms/math/fast-powering)\n  * `B` [طريقة هورنر](src/algorithms/math/horner-method) - تقييم متعدد الحدود\n  * `A` [قسم صحيح](src/algorithms/math/integer-partition)\n  * `A` [الجذر التربيعي](src/algorithms/math/square-root) - طريقة نيوتن\n  * `A` [خوارزمية ليو هوي π](src/algorithms/math/liu-hui) - π حسابات تقريبية على أساس N-gons\n  * `A` [تحويل فورييه المنفصل](src/algorithms/math/fourier-transform) - حلل وظيفة الوقت (إشارة) في الترددات التي يتكون منها\n* **مجموعات**\n  * `B` [المنتج الديكارتي](src/algorithms/sets/cartesian-product) - منتج من مجموعات متعددة\n  * `B` [فيشر ييتس شافل](src/algorithms/sets/fisher-yates) - التقليب العشوائي لتسلسل محدود\n  * `A` [مجموعة الطاقة](src/algorithms/sets/power-set) - جميع المجموعات الفرعية للمجموعة (حلول البت والتتبع التراجعي)\n  * `A` [التباديل](src/algorithms/sets/permutations) (مع وبدون التكرار)\n  * `A` [مجموعات](src/algorithms/sets/combinations) (مع وبدون التكرار)\n  * `A` [أطول نتيجة مشتركة](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [أطول زيادة متتالية](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [أقصر تسلسل فائق مشترك](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [مشكلة حقيبة الظهر](src/algorithms/sets/knapsack-problem) - \"0/1\" و \"غير منضم\"\n  * `A` [الحد الأقصى من Subarray](src/algorithms/sets/maximum-subarray) -إصدارات \"القوة الغاشمة\" و \"البرمجة الديناميكية\" (كادان)\n  * `A` [مجموع الجمع](src/algorithms/sets/combination-sum) - ابحث عن جميع التركيبات التي تشكل مبلغًا محددًا\n* **سلاسل**\n  * `B` [مسافة هامنج](src/algorithms/string/hamming-distance) - عدد المواقف التي تختلف فيها الرموز\n  * `A` [المسافة ليفنشتاين](src/algorithms/string/levenshtein-distance) - الحد الأدنى لمسافة التحرير بين تسلسلين\n  * `A` [خوارزمية كنوث - موريس - برات](src/algorithms/string/knuth-morris-pratt) (خوارزمية KMP) - بحث السلسلة الفرعية (مطابقة النمط)\n  * `A` [خوارزمية Z](src/algorithms/string/z-algorithm) - بحث سلسلة فرعية (مطابقة النمط)\n  * `A` [خوارزمية رابين كارب](src/algorithms/string/rabin-karp) - بحث السلسلة الفرعية\n  * `A` [أطول سلسلة فرعية مشتركة](src/algorithms/string/longest-common-substring)\n  * `A` [مطابقة التعبير العادي](src/algorithms/string/regular-expression-matching)\n* **عمليات البحث**\n  * `B` [البحث الخطي](src/algorithms/search/linear-search)\n  * `B` [بحث سريع](src/algorithms/search/jump-search) (أو حظر البحث) - ابحث في مصفوفة مرتبة\n  * `B` [بحث ثنائي](src/algorithms/search/binary-search) - البحث في مجموعة مرتبة\n  * `B` [بحث الاستيفاء](src/algorithms/search/interpolation-search) - البحث في مجموعة مرتبة موزعة بشكل موحد\n\n* **فرز**\n  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)\n  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)\n  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)\n  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - عمليات التنفيذ في المكان وغير في المكان\n  * `B` [Shellsort](src/algorithms/sorting/shell-sort)\n  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)\n  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)\n* **القوائم المرتبطة**\n  * `B` [Straight Traversal](src/algorithms/linked-list/traversal)\n  * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)\n* **الأشجار**\n  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)\n* **الرسوم البيانية**\n  * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه\n  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) -إيجاد أقصر المسارات لجميع رؤوس الرسم البياني من رأس واحد\n  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - إيجاد أقصر المسارات لجميع رؤوس الرسم البياني من رأس واحد\n  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - إيجاد أقصر المسارات بين جميع أزواج الرؤوس\n  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - لكل من الرسوم البيانية الموجهة وغير الموجهة (الإصدارات القائمة على DFS و Disjoint Set)\n  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه\n  * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - طريقة البحث العمق الأول (DFS)\n  * `A` [Articulation Points](src/algorithms/graph/articulation-points) - خوارزمية تارجان (تعتمد على DFS)\n  * `A` [Bridges](src/algorithms/graph/bridges) - خوارزمية تعتمد على DFS\n  * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - خوارزمية فلوري - قم بزيارة كل حافة مرة واحدة بالضبط\n  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - قم بزيارة كل قمة مرة واحدة بالضبط\n  * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - خوارزمية Kosaraju\n  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - أقصر طريق ممكن يزور كل مدينة ويعود إلى المدينة الأصلية\n* **التشفير\n  * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - المتداول دالة التجزئة على أساس متعدد الحدود\n  * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - استبدال بسيط للشفرات\n* **التعلم الالي**\n  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 وظائف JS بسيطة توضح كيف يمكن للآلات أن تتعلم بالفعل (الانتشار إلى الأمام / الخلف)\n* **غير مصنف**\n  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - خوارزمية في المكان\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - التراجع ، البرمجة الديناميكية (من أعلى إلى أسفل + من أسفل إلى أعلى) والأمثلة الجشعة\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - التراجع والبرمجة الديناميكية والأمثلة القائمة على مثلث باسكال\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار (البرمجة الديناميكية وإصدارات القوة الغاشمة)\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة (4 حلول)\n  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n\n### الخوارزميات حسب النموذج\n\nالنموذج الحسابي هو طريقة أو نهج عام يكمن وراء تصميم الفصل\nمن الخوارزميات. إنه تجريد أعلى من مفهوم الخوارزمية ، تمامًا مثل\nالخوارزمية هي تجريد أعلى من برنامج الكمبيوتر.\n\n* **القوة الغاشمة** - انظر في جميع الاحتمالات وحدد الحل الأفضل\n  * `B` [Linear Search](src/algorithms/search/linear-search)\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)\n  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - أقصر طريق ممكن يزور كل مدينة ويعود إلى المدينة الأصلية\n  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - حلل وظيفة الوقت (إشارة) في الترددات التي يتكون منها\n* **جشع** - اختر الخيار الأفضل في الوقت الحالي ، دون أي اعتبار للمستقبل\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem)\n  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - إيجاد أقصر مسار لجميع رؤوس الرسم البياني\n  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه\n  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه\n* **فرق تسد** - قسّم المشكلة إلى أجزاء أصغر ثم حل تلك الأجزاء\n  * `B` [Binary Search](src/algorithms/search/binary-search)\n  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)\n  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - حساب القاسم المشترك الأكبر (GCD)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort)\n  * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Fast Powering](src/algorithms/math/fast-powering)\n  * `A` [Permutations](src/algorithms/sets/permutations) (مع التكرار وبدونه)\n  * `A` [Combinations](src/algorithms/sets/combinations) (مع التكرار وبدونه)\n* **البرمجة الديناميكية** - بناء حل باستخدام الحلول الفرعية التي تم العثور عليها مسبقًا\n  * `B` [Fibonacci Number](src/algorithms/math/fibonacci)\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة\n  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - الحد الأدنى لمسافة التحرير بين تسلسلين\n  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)\n  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem)\n  * `A` [Integer Partition](src/algorithms/math/integer-partition)\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)\n  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - إيجاد أقصر مسار لجميع رؤوس الرسم البياني\n  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - إيجاد أقصر المسارات بين جميع أزواج الرؤوس\n  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)\n* **التراجع** - على غرار القوة الغاشمة ، حاول إنشاء جميع الحلول الممكنة ، ولكن في كل مرة تقوم فيها بإنشاء الحل التالي الذي تختبره\nإذا استوفت جميع الشروط ، وعندها فقط استمر في إنشاء الحلول اللاحقة. خلاف ذلك ، تراجع ، واذهب إلى\nطريق مختلف لإيجاد حل. عادةً ما يتم استخدام اجتياز DFS لمساحة الدولة.\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  * `B` [Power Set](src/algorithms/sets/power-set) - جميع المجموعات الفرعية للمجموعة\n  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - قم بزيارة كل قمة مرة واحدة بالضبط\n  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - ابحث عن جميع التركيبات التي تشكل مبلغًا محددًا\n\n\n* ** Branch & Bound ** - تذكر الحل الأقل تكلفة الموجود في كل مرحلة من مراحل التراجع\nالبحث ، واستخدام تكلفة الحل الأقل تكلفة الموجود حتى الآن بحد أدنى لتكلفة\nالحل الأقل تكلفة للمشكلة ، من أجل تجاهل الحلول الجزئية بتكاليف أكبر من\nتم العثور على حل بأقل تكلفة حتى الآن. اجتياز BFS عادةً بالاشتراك مع اجتياز DFS لمساحة الحالة\nيتم استخدام الشجرة.\n\n## كيفية استخدام هذا المستودع\n\n**تثبيت كل التبعيات**\n```\nnpm install\n```\n\n**قم بتشغيل ESLint**\n\nقد ترغب في تشغيله للتحقق من جودة الكود.\n\n```\nnpm run lint\n```\n\n**قم بإجراء جميع الاختبارات**\n```\nnpm test\n```\n\n**قم بإجراء الاختبارات بالاسم**\n```\nnpm test -- 'LinkedList'\n```\n\n**ملعب**\n\nيمكنك اللعب بهياكل البيانات والخوارزميات في ملف `. /src/playground/playground.js` والكتابة\nاختبارات لها في `./src/playground/__test__/playground.test.js`.\n\nثم قم ببساطة بتشغيل الأمر التالي لاختبار ما إذا كان كود الملعب الخاص بك يعمل كما هو متوقع:\n\n```\nnpm test -- 'playground'\n```\n\n## معلومات مفيدة\n\n### المراجع\n\n[▶ هياكل البيانات والخوارزميات على موقع يوتيوب](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Big O Notation\n\n* يتم استخدام **Big O notation** لتصنيف الخوارزميات وفقًا لكيفية نمو متطلبات وقت التشغيل أو المساحة مع نمو حجم الإدخال.\nقد تجد في الرسم البياني أدناه الأوامر الأكثر شيوعًا لنمو الخوارزميات المحددة في تBig O notation.\n\n![Big O graphs](./assets/big-o-graph.png)\n\nمصدر: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nفيما يلي قائمة ببعض رموز Big O notation الأكثر استخدامًا ومقارنات أدائها مقابل أحجام مختلفة من بيانات الإدخال.\n\n| Big O Notation | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements  |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### تعقيد عمليات بنية البيانات\n\n| Data Structure          | Access    | Search    | Insertion | Deletion  | Comments  |\n| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |\n| **Array**               | 1         | n         | n         | n         |           |\n| **Stack**               | n         | n         | 1         | 1         |           |\n| **Queue**               | n         | n         | 1         | 1         |           |\n| **Linked List**         | n         | n         | 1         | n         |           |\n| **Hash Table**          | -         | n         | n         | n         |في حالة وجود تكاليف دالة تجزئة مثالية ستكون O (1)|\n| **Binary Search Tree**  | n         | n         | n         | n         | في حالة توازن تكاليف الشجرة ستكون O (log (n))|\n| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Bloom Filter**        | -         | 1         | 1         | -         |الإيجابيات الكاذبة ممكنة أثناء البحث|\n\n### تعقيد خوارزميات فرز الصفيف\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | نعم       |           |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | نعم       |           |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | لا        |           |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | لا        |           |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | نعم       |           |\n| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No        | عادةً ما يتم إجراء الفرز السريع في مكانه مع مساحة مكدس O (log (n))|\n| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | لا       |           |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       |r - أكبر رقم في المجموعة|\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | ك - طول أطول مفتاح |\n\n## مؤيدو المشروع\n\n> يمكنك دعم هذا المشروع عبر ❤️️ [GitHub](https://github.com/sponsors/trekhleb) أو ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n[الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0`\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.de-DE.md",
    "content": "# JavaScript-Algorithmen und Datenstrukturen\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nDieses Repository enthält JavaScript Beispiele für viele\ngängige Algorithmen und Datenstrukturen.\n\nJeder Algorithmus und jede Datenstruktur hat eine eigene README\nmit zugehörigen Erklärungen und weiterführenden Links (einschließlich zu YouTube-Videos).\n\n_Lies dies in anderen Sprachen:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/)\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Datenstrukturen\n\nEine Datenstruktur ist eine bestimmte Art und Weise, Daten in einem Computer so zu organisieren und zu speichern, dass sie\neffizient erreicht und verändert werden können. Genauer gesagt, ist eine Datenstruktur eine Sammlung von Werten,\nden Beziehungen zwischen ihnen und den Funktionen oder Operationen, die auf die Daten angewendet werden können.\n\n`B` - Anfänger:innen, `A` - Fortgeschrittene\n\n* `B` [Verkettete Liste (Linked List)](src/data-structures/linked-list)\n* `B` [Doppelt verkettete Liste (Doubly Linked List)](src/data-structures/doubly-linked-list)\n* `B` [Warteschlange (Queue)](src/data-structures/queue)\n* `B` [Stapelspeicher (Stack)](src/data-structures/stack)\n* `B` [Hashtabelle (Hash Table)](src/data-structures/hash-table)\n* `B` [Heap-Algorithmus (Heap)](src/data-structures/heap) - max und min Heap-Versionen\n* `B` [Vorrangwarteschlange (Priority Queue)](src/data-structures/priority-queue)\n* `A` [Trie (Trie)](src/data-structures/trie)\n* `A` [Baum (Tree)](src/data-structures/tree)\n  * `A` [Binärer Suchbaum (Binary Search Tree)](src/data-structures/tree/binary-search-tree)\n  * `A` [AVL-Baum (AVL Tree)](src/data-structures/tree/avl-tree)\n  * `A` [Rot-Schwarz-Baum (Red-Black Tree)](src/data-structures/tree/red-black-tree)\n  * `A` [Segment-Baum (Segment Tree)](src/data-structures/tree/segment-tree) - mit Min/Max/Summenbereich-Abfrage Beispiel\n  * `A` [Fenwick Baum (Fenwick Tree)](src/data-structures/tree/fenwick-tree) (Binär indizierter Baum / Binary Indexed Tree)\n* `A` [Graph (Graph)](src/data-structures/graph) (sowohl gerichtet als auch ungerichtet)\n* `A` [Union-Find-Struktur (Disjoint Set)](src/data-structures/disjoint-set)\n* `A` [Bloomfilter (Bloom Filter)](src/data-structures/bloom-filter)\n\n## Algorithmen\n\nEin Algorithmus ist eine eindeutige Spezifikation, wie eine Klasse von Problemen zu lösen ist. Er besteht\naus einem Satz von Regeln, die eine Abfolge von Operationen genau definieren.\n\n`B` - Anfänger:innen, `A` - Fortgeschrittene\n\n### Algorithmen nach Thema\n\n* **Mathe**\n  * `B` [Bitmanipulation (Bit Manipulation)](src/algorithms/math/bits) - Bits setzen/lesen/aktualisieren/löschen, Multiplikation/Division durch zwei negieren usw..\n  * `B` [Faktoriell (Factorial)](src/algorithms/math/factorial)\n  * `B` [Fibonacci-Zahl (Fibonacci Number)](src/algorithms/math/fibonacci) - Klassische und geschlossene Version\n  * `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)\n  * `B` [Primzahl-Test (Primality Test)](src/algorithms/math/primality-test) (Probedivision / trial division method)\n  * `B` [Euklidischer Algorithmus (Euclidean Algorithm)](src/algorithms/math/euclidean-algorithm) - Berechnen des größten gemeinsamen Teilers (ggT)\n  * `B` [Kleinstes gemeinsames Vielfaches (Least Common Multiple)](src/algorithms/math/least-common-multiple) (kgV)\n  * `B` [Sieb des Eratosthenes (Sieve of Eratosthenes)](src/algorithms/math/sieve-of-eratosthenes) - Finden aller Primzahlen bis zu einer bestimmten Grenze\n  * `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)\n  * `B` [Pascalsches Dreieck (Pascal's Triangle)](src/algorithms/math/pascal-triangle)\n  * `B` [Komplexe Zahlen (Complex Number)](src/algorithms/math/complex-number) - Komplexe Zahlen und Grundoperationen mit ihnen\n  * `B` [Bogenmaß & Grad (Radian & Degree)](src/algorithms/math/radian) - Umrechnung von Bogenmaß in Grad und zurück\n  * `B` [Fast Powering Algorithmus (Fast Powering)](src/algorithms/math/fast-powering)\n  * `B` [Horner-Schema (Horner's method)](src/algorithms/math/horner-method) - Polynomauswertung\n  * `B` [Matrizen (Matrices)](src/algorithms/math/matrix) - Matrizen und grundlegende Matrixoperationen (Multiplikation, Transposition usw.)\n  * `B` [Euklidischer Abstand (Euclidean Distance)](src/algorithms/math/euclidean-distance) - Abstand zwischen zwei Punkten/Vektoren/Matrizen\n  * `A` [Ganzzahlige Partitionierung (Integer Partition)](src/algorithms/math/integer-partition)\n  * `A` [Quadratwurzel (Square Root)](src/algorithms/math/square-root) - Newtonverfahren (Newton's method)\n  * `A` [Liu Hui π Algorithmus (Liu Hui π Algorithm)](src/algorithms/math/liu-hui) - Näherungsweise π-Berechnungen auf Basis von N-gons\n  * `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\n* **Sets**\n  * `B` [Kartesisches Produkt (Cartesian Product)](src/algorithms/sets/cartesian-product) - Produkt aus mehreren Mengen\n  * `B` [Fisher-Yates-Verfahren (Fisher–Yates Shuffle)](src/algorithms/sets/fisher-yates) - Zufällige Permutation einer endlichen Folge\n  * `A` [Potenzmenge (Power Set)](src/algorithms/sets/power-set) - Alle Teilmengen einer Menge (Bitweise und Rücksetzverfahren Lösungen(backtracking solutions))\n  * `A` [Permutation (Permutations)](src/algorithms/sets/permutations) (mit und ohne Wiederholungen)\n  * `A` [Kombination (Combinations)](src/algorithms/sets/combinations) (mit und ohne Wiederholungen)\n  * `A` [Problem der längsten gemeinsamen Teilsequenz (Longest Common Subsequence)](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Längste gemeinsame Teilsequenz (Longest Increasing Subsequence)](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Der kürzeste gemeinsame String (Shortest Common Supersequence)](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Rucksackproblem (Knapsack Problem)](src/algorithms/sets/knapsack-problem) - \"0/1\" und \"Ungebunden\"\n  * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray) - \"Brute-Force-Methode\" und \"Dynamische Programmierung\" (Kadane' Algorithmus)\n  * `A` [Kombinationssumme (Combination Sum)](src/algorithms/sets/combination-sum) - Alle Kombinationen finden, die eine bestimmte Summe bilden\n* **Zeichenketten (Strings)**\n  * `B` [Hamming-Abstand (Hamming Distance)](src/algorithms/string/hamming-distance) - Anzahl der Positionen, an denen die Symbole unterschiedlich sind\n  * `A` [Levenshtein-Distanz (Levenshtein Distance)](src/algorithms/string/levenshtein-distance) - Minimaler Editierabstand zwischen zwei Sequenzen\n  * `A` [Knuth-Morris-Pratt-Algorithmus (Knuth–Morris–Pratt Algorithm)](src/algorithms/string/knuth-morris-pratt) (KMP Algorithmus) - Teilstringsuche (Mustervergleich / Pattern Matching)\n  * `A` [Z-Algorithmus (Z Algorithm)](src/algorithms/string/z-algorithm) - Teilstringsuche (Mustervergleich / Pattern Matching)\n  * `A` [Rabin-Karp-Algorithmus (Rabin Karp Algorithm)](src/algorithms/string/rabin-karp) - Teilstringsuche\n  * `A` [Längstes häufiges Teilzeichenfolgenproblem (Longest Common Substring)](src/algorithms/string/longest-common-substring)\n  * `A` [Regulärer Ausdruck (Regular Expression Matching)](src/algorithms/string/regular-expression-matching)\n* **Suchen**\n  * `B` [Lineare Suche (Linear Search)](src/algorithms/search/linear-search)\n  * `B` [Sprungsuche (Jump Search)](src/algorithms/search/jump-search) (oder Blocksuche) - Suche im sortierten Array\n  * `B` [Binäre Suche (Binary Search)](src/algorithms/search/binary-search) - Suche in einem sortierten Array\n  * `B` [Interpolationssuche (Interpolation Search)](src/algorithms/search/interpolation-search) - Suche in gleichmäßig verteilt sortiertem Array\n* **Sortieren**\n  * `B` [Bubblesort (Bubble Sort)](src/algorithms/sorting/bubble-sort)\n  * `B` [Selectionsort (Selection Sort)](src/algorithms/sorting/selection-sort)\n  * `B` [Einfügesortierenmethode (Insertion Sort)](src/algorithms/sorting/insertion-sort)\n  * `B` [Haldensortierung (Heap Sort)](src/algorithms/sorting/heap-sort)\n  * `B` [Mergesort (Merge Sort)](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort (Quicksort)](src/algorithms/sorting/quick-sort) - in-place und non-in-place Implementierungen\n  * `B` [Shellsort (Shellsort)](src/algorithms/sorting/shell-sort)\n  * `B` [Countingsort (Counting Sort)](src/algorithms/sorting/counting-sort)\n  * `B` [Fachverteilen (Radix Sort)](src/algorithms/sorting/radix-sort)\n* **Verkettete Liste (Linked List)**\n  * `B` [Gerade Traversierung (Straight Traversal)](src/algorithms/linked-list/traversal)\n  * `B` [Umgekehrte Traversierung (Reverse Traversal)](src/algorithms/linked-list/reverse-traversal)\n* **Bäume**\n  * `B` [Tiefensuche (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Breitensuche (Breadth-First Search)](src/algorithms/tree/breadth-first-search) (BFS)\n* **Graphen**\n  * `B` [Tiefensuche (Depth-First Search)](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Breitensuche (Breadth-First Search)](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Algorithmus von Kruskal (Kruskal’s Algorithm)](src/algorithms/graph/kruskal) - Finden des Spannbaum (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen\n  * `A` [Dijkstra-Algorithmus (Dijkstra Algorithm)](src/algorithms/graph/dijkstra) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus\n  * `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\n  * `A` [Algorithmus von Floyd und Warshall (Floyd-Warshall Algorithm)](src/algorithms/graph/floyd-warshall) - Die kürzesten Wege zwischen allen Knotenpaaren finden\n  * `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)\n  * `A` [Algorithmus von Prim (Prim’s Algorithm)](src/algorithms/graph/prim) - Finden des Spannbaums (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen\n  * `A` [Topologische Sortierung (Topological Sorting)](src/algorithms/graph/topological-sorting) - DFS-Verfahren\n  * `A` [Artikulationspunkte (Articulation Points)](src/algorithms/graph/articulation-points) - Algorithmus von Tarjan (Tarjan's algorithm) (DFS basiert)\n  * `A` [Brücke (Bridges)](src/algorithms/graph/bridges) - DFS-basierter Algorithmus\n  * `A` [Eulerkreisproblem (Eulerian Path and Eulerian Circuit)](src/algorithms/graph/eulerian-path) - Algorithmus von Fleury (Fleury's algorithm) - Jede Kante genau einmal durchlaufen.\n  * `A` [Hamiltonkreisproblem (Hamiltonian Cycle)](src/algorithms/graph/hamiltonian-cycle) - Jeden Eckpunkt genau einmal durchlaufen.\n  * `A` [Starke Zusammenhangskomponente (Strongly Connected Components)](src/algorithms/graph/strongly-connected-components) - Kosarajus Algorithmus\n  * `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\n* **Kryptographie**\n  * `B` [Polynomiale Streuwertfunktion(Polynomial Hash)](src/algorithms/cryptography/polynomial-hash) - Rollierende Streuwert-Funktion basierend auf Polynom\n  * `B` [Schienenzaun Chiffre (Rail Fence Cipher)](src/algorithms/cryptography/rail-fence-cipher) - Ein Transpositionsalgorithmus zur Verschlüsselung von Nachrichten\n  * `B` [Caesar-Verschlüsselung (Caesar Cipher)](src/algorithms/cryptography/caesar-cipher) - Einfache Substitutions-Chiffre\n  * `B` [Hill-Chiffre (Hill Cipher)](src/algorithms/cryptography/hill-cipher) - Substitutionschiffre basierend auf linearer Algebra\n* **Maschinelles Lernen**\n  * `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)\n  * `B` [Nächste-Nachbarn-Klassifikation (k-NN)](src/algorithms/ml/knn) - k-nächste-Nachbarn-Algorithmus\n  * `B` [k-Means (k-Means)](src/algorithms/ml/k-means) - k-Means-Algorithmus\n* **Image Processing**\n  * `B` [Inhaltsabhängige Bildverzerrung (Seam Carving)](src/algorithms/image-processing/seam-carving) - Algorithmus zur inhaltsabhängigen Bildgrößenänderung\n* **Unkategorisiert**\n  * `B` [Türme von Hanoi (Tower of Hanoi)](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Rotationsmatrix (Square Matrix Rotation)](src/algorithms/uncategorized/square-matrix-rotation) - In-Place-Algorithmus\n  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game) - Backtracking, dynamische Programmierung (Top-down + Bottom-up) und gierige Beispiele\n  * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths) - Backtracking, dynamische Programmierung und Pascalsches Dreieck basierte Beispiele\n  * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen)\n  * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen)\n  * `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\n  * `A` [Damenproblem (N-Queens Problem)](src/algorithms/uncategorized/n-queens)\n  * `A` [Springerproblem (Knight's Tour)](src/algorithms/uncategorized/knight-tour)\n\n### Algorithmen nach Paradigma\n\nEin 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.\n\n* **Brachiale Gewalt (Brute Force)** - schaut sich alle Möglichkeiten an und wählt die beste Lösung aus\n  * `B` [Lineare Suche (Linear Search)](src/algorithms/search/linear-search)\n  * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen)\n  * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen)\n  * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray)\n  * `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\n  * `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\n* **Gierig (Greedy)** - Wählt die beste Option zum aktuellen Zeitpunkt, ohne Rücksicht auf die Zukunft\n  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)\n  * `A` [Rucksackproblem (Unbound Knapsack Problem)](src/algorithms/sets/knapsack-problem)\n  * `A` [Dijkstra-Algorithmus (Dijkstra Algorithm)](src/algorithms/graph/dijkstra) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus\n  * `A` [Algorithmus von Prim (Prim’s Algorithm)](src/algorithms/graph/prim) - Finden des Spannbaums (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen\n  * `B` [Algorithmus von Kruskal (Kruskal’s Algorithm)](src/algorithms/graph/kruskal) - Finden des Spannbaum (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen\n* **Teile und herrsche** - Das Problem in kleinere Teile aufteilen und diese Teile dann lösen\n  * `B` [Binäre Suche (Binary Search)](src/algorithms/search/binary-search)\n  * `B` [Türme von Hanoi (Tower of Hanoi)](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Pascalsches Dreieck (Pascal's Triangle)](src/algorithms/math/pascal-triangle)\n  * `B` [Euklidischer Algorithmus (Euclidean Algorithm)](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)\n  * `B` [Mergesort (Merge Sort)](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort (Quicksort)](src/algorithms/sorting/quick-sort)\n  * `B` [Tiefensuche (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Breitensuche (Breadth-First Search)](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Matrizen (Matrices)](src/algorithms/math/matrix) - Matrizen und grundlegende Matrixoperationen (Multiplikation, Transposition usw.)\n  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)\n  * `B` [Fast Powering Algorithmus (Fast Powering)](src/algorithms/math/fast-powering)\n  * `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\n  * `A` [Permutation (Permutations)](src/algorithms/sets/permutations) (mit und ohne Wiederholungen)\n  * `A` [Kombination (Combinations)](src/algorithms/sets/combinations) (mit und ohne Wiederholungen)\n* **Dynamische Programmierung** - Eine Lösung aus zuvor gefundenen Teillösungen aufbauen\n  * `B` [Fibonacci-Zahl (Fibonacci Number)](src/algorithms/math/fibonacci)\n  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)\n  * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths)\n  * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen)\n  * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen)\n  * `B` [Inhaltsabhängige Bildverzerrung (Seam Carving)](src/algorithms/image-processing/seam-carving) - Algorithmus zur inhaltsabhängigen Bildgrößenänderung\n  * `A` [Levenshtein-Distanz (Levenshtein Distance)](src/algorithms/string/levenshtein-distance) - Minimaler Editierabstand zwischen zwei Sequenzen\n  * `A` [Problem der längsten gemeinsamen Teilsequenz (Longest Common Subsequence)](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Längstes häufiges Teilzeichenfolgenproblem (Longest Common Substring)](src/algorithms/string/longest-common-substring)\n  * `A` [Längste gemeinsame Teilsequenz (Longest Increasing Subsequence)](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Der kürzeste gemeinsame String (Shortest Common Supersequence)](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Rucksackproblem (0/1 Knapsack Problem)](src/algorithms/sets/knapsack-problem)\n  * `A` [Ganzzahlige Partitionierung (Integer Partition)](src/algorithms/math/integer-partition)\n  * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray)\n  * `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\n  * `A` [Algorithmus von Floyd und Warshall (Floyd-Warshall Algorithm)](src/algorithms/graph/floyd-warshall) - Die kürzesten Wege zwischen allen Knotenpaaren finden\n  * `A` [Regulärer Ausdruck (Regular Expression Matching)](src/algorithms/string/regular-expression-matching)\n* **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.\n  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)\n  * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths)\n  * `A` [Potenzmenge (Power Set)](src/algorithms/sets/power-set) - Alle Teilmengen einer Menge\n  * `A` [Hamiltonkreisproblem (Hamiltonian Cycle)](src/algorithms/graph/hamiltonian-cycle) - Jeden Eckpunkt genau einmal durchlaufen.\n  * `A` [Damenproblem (N-Queens Problem)](src/algorithms/uncategorized/n-queens)\n  * `A` [Springerproblem (Knight's Tour)](src/algorithms/uncategorized/knight-tour)\n  * `A` [Kombinationssumme (Combination Sum)](src/algorithms/sets/combination-sum) - Alle Kombinationen finden, die eine bestimmte Summe bilden\n* **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.\n\n## So verwendest du dieses Repository\n\n**Alle Abhängigkeiten installieren**\n\n```\nnpm install\n```\n\n**ESLint ausführen**\n\nYou may want to run it to check code quality.\n\n```\nnpm run lint\n```\n\n**Alle Tests ausführen**\n\n```\nnpm test\n```\n\n**Tests nach Namen ausführen**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**Fehlerbehebung**\n\nFalls das Linting oder Testen fehlschlägt, versuche, den Ordner \"node_modules\" zu löschen und die npm-Pakete neu zu installieren:\n\n```\nrm -rf ./node_modules\nnpm i\n```\n\n**Spielwiese**\n\nDu kannst mit Datenstrukturen und Algorithmen in der Datei `./src/playground/playground.js` herumspielen und\ndir in dieser Datei Tests schreiben `./src/playground/__test__/playground.test.js`.\n\nDann führe einfach folgenden Befehl aus, um zu testen, ob dein Spielwiesencode wie erwartet funktioniert:\n\n```\nnpm test -- 'playground'\n```\n\n## Nützliche Informationen\n\n### Referenzen\n\n[▶ Datenstrukturen und Algorithmen auf YouTube(Englisch)](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### O-Notation (_Big O Notation_)\n\nDie 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.\n\n![O-Notation Graphen](./assets/big-o-graph.png)\n\nQuelle: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nNachfolgend finden Sie eine Liste einiger der am häufigsten verwendeten Big O-Notationen und deren Leistungsvergleiche für unterschiedliche Größen der Eingabedaten.\n\n| Big O Notation | Berechnungen für 10 Elemente | Berechnungen für 100 Elemente | Berechnungen für 1000 Elemente |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------ |\n| **O(1)**       | 1                            | 1                             | 1                              |\n| **O(log N)**   | 3                            | 6                             | 9                              |\n| **O(N)**       | 10                           | 100                           | 1000                           |\n| **O(N log N)** | 30                           | 600                           | 9000                           |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                        |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                      |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                     |\n\n### Komplexität von Datenstrukturoperationen\n\n| Datenstruktur          | Zugriff auf | Suche  | Einfügen | Löschung | Kommentare                                                      |\n| ---------------------- | :---------: | :----: | :------: | :------: | :-------------------------------------------------------------- |\n| **Array**              |      1      |   n    |    n     |    n     |                                                                 |\n| **Stack**              |      n      |   n    |    1     |    1     |                                                                 |\n| **Queue**              |      n      |   n    |    1     |    1     |                                                                 |\n| **Linked List**        |      n      |   n    |    1     |    n     |                                                                 |\n| **Hash Table**         |      -      |   n    |    n     |    n     | Im Falle einer perfekten Hash-Funktion wären die Kosten O(1)    |\n| **Binary Search Tree** |      n      |   n    |    n     |    n     | Im Falle eines ausgeglichenen Baumes wären die Kosten O(log(n)) |\n| **B-Tree**             |   log(n)    | log(n) |  log(n)  |  log(n)  |                                                                 |\n| **Red-Black Tree**     |   log(n)    | log(n) |  log(n)  |  log(n)  |                                                                 |\n| **AVL Tree**           |   log(n)    | log(n) |  log(n)  |  log(n)  |                                                                 |\n| **Bloom Filter**       |      -      |   1    |    1     |    -     | Falschpostive sind bei der Suche möglichen                      |\n\n### Komplexität von Array-Sortieralgorithmen\n\n| Name               |    Bester     |      Durchschnitt       |        Schlechtester        | Speicher | Stabil | Kommentar                                                                  |\n| ------------------ | :-----------: | :---------------------: | :-------------------------: | :------: | :----: | :------------------------------------------------------------------------- |\n| **Bubble sort**    |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |    1     |   JA   |                                                                            |\n| **Insertion sort** |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |    1     |   Ja   |                                                                            |\n| **Selection sort** | n<sup>2</sup> |      n<sup>2</sup>      |        n<sup>2</sup>        |    1     |  Nein  |                                                                            |\n| **Heap sort**      | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |    1     |  Nein  |                                                                            |\n| **Merge sort**     | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |    n     |   Ja   |                                                                            |\n| **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 |\n| **Shell sort**     | n&nbsp;log(n) | abhängig von Spaltfolge | n&nbsp;(log(n))<sup>2</sup> |    1     |  Nein  |                                                                            |\n| **Counting sort**  |     n + r     |          n + r          |            n + r            |  n + r   |   Ja   | r - größte Zahl im Array                                                   |\n| **Radix sort**     |    n \\* k     |         n \\* k          |           n \\* k            |  n + k   |   Ja   | k - Länge des längsten Schlüssels                                          |\n\n## Projekt-Unterstützer\n\n> Du kannst dieses Projekt unterstützen über ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n[Leute, die dieses Projekt unterstützen](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0`\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n\n"
  },
  {
    "path": "README.es-ES.md",
    "content": "# Algoritmos y Estructuras de Datos en JavaScript\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nEste repositorio contiene ejemplos basados en JavaScript de muchos\nalgoritmos y estructuras de datos populares.\n\nCada algoritmo y estructura de datos tiene su propio LÉAME con explicaciones relacionadas y\nenlaces para lecturas adicionales (incluyendo algunas a vídeos de YouTube).\n\n_Léelo en otros idiomas:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Estructuras de Datos\n\nUna estructura de datos es una forma particular de organizar y almacenar datos en un ordenador para que puedan accederse\ny modificarse de forma eficiente. Más concretamente, una estructura de datos es un conjunto de valores\nde datos, las relaciones entre ellos y las funciones u operaciones que se pueden aplicar a\nlos datos.\n\n`P` - Principiante, `A` - Avanzado\n\n* `P` [Lista enlazada](src/data-structures/linked-list)\n* `P` [Lista doblemente enlazada](src/data-structures/doubly-linked-list)\n* `P` [Cola](src/data-structures/queue)\n* `P` [Pila](src/data-structures/stack)\n* `P` [Tabla hash](src/data-structures/hash-table)\n* `P` [Heap](src/data-structures/heap) - versiones máx y mín\n* `P` [Cola de prioridad](src/data-structures/priority-queue)\n* `A` [Trie](src/data-structures/trie)\n* `A` [Árbol](src/data-structures/tree)\n  * `A` [Árbol de búsqueda binaria](src/data-structures/tree/binary-search-tree)\n  * `A` [Árbol AVL](src/data-structures/tree/avl-tree)\n  * `A` [Árbol Rojo-Negro](src/data-structures/tree/red-black-tree)\n  * `A` [Árbol de segmentos](src/data-structures/tree/segment-tree) - con ejemplos de consultas de rango mín/máx/suma\n  * `A` [Árbol de Fenwick](src/data-structures/tree/fenwick-tree) (Árbol binario indexado)\n* `A` [Grafo](src/data-structures/graph) (dirigido y no dirigido)\n* `A` [Conjuntos disjuntos](src/data-structures/disjoint-set)\n* `A` [Filtro de Bloom](src/data-structures/bloom-filter)\n\n## Algoritmos\n\nUn algoritmo es una especificación inequívoca de cómo resolver una clase de problemas. Es un conjunto de reglas que\ndefinen con precisión una secuencia de operaciones.\n\n`P` - Principiante, `A` - Avanzado\n\n### Algoritmos por Tema\n\n* **Matemáticas**\n  * `P` [Manipulación de bits](src/algorithms/math/bits) - asignar/obtener/actualizar/limpiar bits, multiplicación/división por dos, hacer negativo, etc.\n  * `P` [Factorial](src/algorithms/math/factorial)\n  * `P` [Sucesión de Fibonacci](src/algorithms/math/fibonacci)\n  * `P` [Prueba de primalidad](src/algorithms/math/primality-test) (método de división de prueba)\n  * `P` [Algoritmo de Euclides](src/algorithms/math/euclidean-algorithm) - calcular el Máximo común divisor (MCD)\n  * `P` [Mínimo común múltiplo](src/algorithms/math/least-common-multiple) (MCM)\n  * `P` [Criba de Eratóstenes](src/algorithms/math/sieve-of-eratosthenes) - encontrar todos los números primos hasta un límite dado\n  * `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)\n  * `P` [Triángulo de Pascal](src/algorithms/math/pascal-triangle)\n  * `P` [Números complejos](src/algorithms/math/complex-number) - números complejos y operaciones con ellos\n  * `P` [Radianes & Grados](src/algorithms/math/radian) - conversión de radianes a grados y viceversa\n  * `P` [Exponenciación rápida](src/algorithms/math/fast-powering)\n  * `A` [Partición entera](src/algorithms/math/integer-partition)\n  * `A` [Algoritmo π de Liu Hui](src/algorithms/math/liu-hui) - aproximar el cálculo de  π basado en polígonos de N lados\n  * `A` [Transformada discreta de Fourier](src/algorithms/math/fourier-transform) - descomponer una función de tiempo (señal) en las frecuencias que la componen\n* **Conjuntos**\n  * `P` [Producto cartesiano](src/algorithms/sets/cartesian-product) - producto de múltiples conjuntos\n  * `P` [Permutación de Fisher–Yates](src/algorithms/sets/fisher-yates) - permutación aleatoria de una secuencia finita\n  * `A` [Conjunto potencia](src/algorithms/sets/power-set) - todos los subconjuntos de un conjunto\n  * `A` [Permutaciones](src/algorithms/sets/permutations) (con y sin repeticiones)\n  * `A` [Combinaciones](src/algorithms/sets/combinations) (con y sin repeticiones)\n  * `A` [Subsecuencia común más larga](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Subsecuencia creciente más larga](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Supersecuencia común más corta](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Problema de la mochila](src/algorithms/sets/knapsack-problem) - \"0/1\" y \"sin límite\"\n  * `A` [Máximo subarreglo](src/algorithms/sets/maximum-subarray) - versiones de \"fuerza bruta\" y \"programación dinámica\" (de Kadane)\n  * `A` [Suma combinada](src/algorithms/sets/combination-sum) - encuentra todas las combinaciones que forman una suma específica\n* **Cadenas de caracteres**\n  * `P` [Distancia de Hamming](src/algorithms/string/hamming-distance) - número de posiciones en las que los símbolos son diferentes\n  * `A` [Distancia de Levenshtein](src/algorithms/string/levenshtein-distance) - distancia mínima de edición entre dos secuencias\n  * `A` [Algoritmo Knuth-Morris-Pratt](src/algorithms/string/knuth-morris-pratt) (Algoritmo KMP) - búsqueda de subcadenas (coincidencia de patrones)\n  * `A` [Algoritmo Z](src/algorithms/string/z-algorithm) - búsqueda de subcadenas (coincidencia de patrones)\n  * `A` [Algoritmo de Rabin Karp](src/algorithms/string/rabin-karp) - búsqueda de subcadenas\n  * `A` [Subcadena común más larga](src/algorithms/string/longest-common-substring)\n  * `A` [Coincidencia por expresiones regulares](src/algorithms/string/regular-expression-matching)\n* **Búsquedas**\n  * `P` [Búsqueda lineal](src/algorithms/search/linear-search)\n  * `P` [Búsqueda de salto](src/algorithms/search/jump-search) (o Búsqueda de bloque) - búsqueda en una lista ordenada\n  * `P` [Búsqueda binaria](src/algorithms/search/binary-search) - búsqueda en una lista ordenada\n  * `P` [Búsqueda por interpolación](src/algorithms/search/interpolation-search) - búsqueda en una lista ordenada uniformemente distribuida\n* **Ordenamiento**\n  * `P` [Ordenamiento de burbuja](src/algorithms/sorting/bubble-sort)\n  * `P` [Ordenamiento por selección](src/algorithms/sorting/selection-sort)\n  * `P` [Ordenamiento por inserción](src/algorithms/sorting/insertion-sort)\n  * `P` [Ordenamiento por Heap](src/algorithms/sorting/heap-sort)\n  * `P` [Ordenamiento por mezcla](src/algorithms/sorting/merge-sort)\n  * `P` [Quicksort](src/algorithms/sorting/quick-sort) - implementaciones in situ y no in situ\n  * `P` [Shellsort](src/algorithms/sorting/shell-sort)\n  * `P` [Ordenamiento por cuentas](src/algorithms/sorting/counting-sort)\n  * `P` [Ordenamiento Radix](src/algorithms/sorting/radix-sort)\n* **Listas enlazadas**\n  * `P` [Recorrido directo](src/algorithms/linked-list/traversal)\n  * `P` [Recorrido inverso](src/algorithms/linked-list/reverse-traversal)\n* **Árboles**\n  * `P` [Búsqueda en profundidad](src/algorithms/tree/depth-first-search) (DFS)\n  * `P` [Búsqueda en anchura](src/algorithms/tree/breadth-first-search) (BFS)\n* **Grafos**\n  * `P` [Búsqueda en profundidad](src/algorithms/graph/depth-first-search) (DFS)\n  * `P` [Búsqueda en anchura](src/algorithms/graph/breadth-first-search) (BFS)\n  * `P` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado\n  * `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\n  * `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\n  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - encontrar los caminos más cortos entre todos los pares de vértices\n  * `A` [Detectar ciclos](src/algorithms/graph/detect-cycle) - para grafos dirigidos y no dirigidos (versiones basadas en DFS y conjuntos disjuntos)\n  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado\n  * `A` [Ordenamiento topológico](src/algorithms/graph/topological-sorting) - método DFS\n  * `A` [Puntos de articulación](src/algorithms/graph/articulation-points) - algoritmo de Tarjan (basado en DFS)\n  * `A` [Puentes](src/algorithms/graph/bridges) - algoritmo basado en DFS\n  * `A` [Camino euleriano y circuito euleriano](src/algorithms/graph/eulerian-path) - algoritmo de Fleury - visitar cada arista exactamente una vez\n  * `A` [Ciclo hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - visitar cada vértice exactamente una vez\n  * `A` [Componentes fuertemente conexos](src/algorithms/graph/strongly-connected-components) - algoritmo de Kosaraju\n  * `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\n* **Criptografía**\n  * `P` [Hash polinomial](src/algorithms/cryptography/polynomial-hash) - función de hash rodante basada en polinomio\n* **Sin categoría**\n  * `P` [Torre de Hanói](src/algorithms/uncategorized/hanoi-tower)\n  * `P` [Rotación de matriz cuadrada](src/algorithms/uncategorized/square-matrix-rotation) - algoritmo in situ\n  * `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\n  * `P` [Caminos únicos](src/algorithms/uncategorized/unique-paths) - ejemplos de backtracking, programación dinámica y basados en el Triángulo de Pascal\n  * `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)\n  * `A` [Problema de las N Reinas](src/algorithms/uncategorized/n-queens)\n  * `A` [Problema del caballo (Knight tour)](src/algorithms/uncategorized/knight-tour)\n\n### Algoritmos por paradigma\n\nUn paradigma algorítmico es un método o enfoque genérico que subyace al diseño de una clase de algoritmos.\nEs 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.\n\n* **Fuerza Bruta** - mira todas las posibilidades y selecciona la mejor solución\n  * `P` [Búsqueda lineal](src/algorithms/search/linear-search)\n  * `P` [Terrazas pluviales](src/algorithms/uncategorized/rain-terraces) - el problema de la retención del agua de lluvia\n  * `A` [Máximo subarreglo](src/algorithms/sets/maximum-subarray)\n  * `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\n  * `A` [Transformada discreta de Fourier](src/algorithms/math/fourier-transform) - descomponer una función de tiempo (señal) en las frecuencias que la componen\n* **Voraces** - escoge la mejor opción en el momento actual, sin ninguna consideración sobre el futuro\n  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)\n  * `A` [Problema de la mochila sin límite](src/algorithms/sets/knapsack-problem)\n  * `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\n  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado\n  * `A` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado\n* **Divide y Vencerás** - divide el problema en partes más pequeñas y luego resuelve esas partes\n  * `P` [Búsqueda binaria](src/algorithms/search/binary-search)\n  * `P` [Torre de Hanói](src/algorithms/uncategorized/hanoi-tower)\n  * `P` [Triángulo de Pascal](src/algorithms/math/pascal-triangle)\n  * `P` [Algoritmo de Euclides](src/algorithms/math/euclidean-algorithm) - calcular el Máximo Común Divisor (MCD)\n  * `P` [Ordenamiento por mezcla](src/algorithms/sorting/merge-sort)\n  * `P` [Quicksort](src/algorithms/sorting/quick-sort)\n  * `P` [Búsqueda en profundidad (árboles)](src/algorithms/tree/depth-first-search) - (DFS)\n  * `P` [Búsqueda en profundidad (grafos)](src/algorithms/graph/depth-first-search) - (DFS)\n  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)\n  * `P` [Exponenciación rápida](src/algorithms/math/fast-powering)\n  * `A` [Permutaciones](src/algorithms/sets/permutations) - (con y sin repeticiones)\n  * `A` [Combinaciones](src/algorithms/sets/combinations) - (con y sin repeticiones)\n* **Programación Dinámica** - construye una solución usando sub-soluciones previamente encontradas\n  * `P` [Número de Fibonacci](src/algorithms/math/fibonacci)\n  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)\n  * `P` [Caminos únicos](src/algorithms/uncategorized/unique-paths)\n  * `P` [Terrazas pluviales](src/algorithms/uncategorized/rain-terraces) - el problema de la retención del agua de lluvia\n  * `A` [Distancia de Levenshtein](src/algorithms/string/levenshtein-distance) - distancia mínima de edición entre dos secuencias\n  * `A` [Subsecuencia común más larga](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Subcadena común más larga](src/algorithms/string/longest-common-substring)\n  * `A` [Subsecuencia creciente más larga](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Supersecuencia común más corta](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Problema de la mochila 0/1](src/algorithms/sets/knapsack-problem)\n  * `A` [Partición entera](src/algorithms/math/integer-partition)\n  * `A` [Máximo subarreglo](src/algorithms/sets/maximum-subarray)\n  * `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\n  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - encontrar los caminos más cortos entre todos los pares de vértices\n  * `A` [Coincidencia por expresiones regulares](src/algorithms/string/regular-expression-matching)\n* **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.\n  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)\n  * `P` [Caminos únicos](src/algorithms/uncategorized/unique-paths)\n  * `P` [Conjunto potencia](src/algorithms/sets/power-set) - todos los subconjuntos de un conjunto\n  * `A` [Ciclo hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - visitar cada vértice exactamente una vez\n  * `A` [Problema de las N Reinas](src/algorithms/uncategorized/n-queens)\n  * `A` [Problema del caballo (Knight tour)](src/algorithms/uncategorized/knight-tour)\n  * `A` [Suma combinada](src/algorithms/sets/combination-sum) - encuentra todas las combinaciones que forman una suma específica\n* **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.\n\n## Cómo usar este repositorio\n\n**Instalar las dependencias**\n\n```\nnpm install\n```\n\n**Correr ESLint**\n\nEs posible que desee ejecutarlo para comprobar la calidad del código.\n\n```\nnpm run lint\n```\n\n**Correr los tests**\n\n```\nnpm test\n```\n\n**Correr tests por nombre**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**Campo de juegos**\n\nPuede jugar con estructuras de datos y algoritmos en el archivo `./src/playground/playground.js` y escribir\npruebas para ello en `./src/playground/__test__/playground.test.js`.\n\nA continuación, simplemente ejecute el siguiente comando para comprobar si el código funciona como se espera:\n\n```\nnpm test -- 'playground'\n```\n\n## Información útil\n\n### Referencias\n\n[▶ Estructuras de datos y algoritmos en YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Notación O Grande\n\nOrden de crecimiento de los algoritmos especificados en la notación O grande.\n\n![Gráficas de Notación O grande ](./assets/big-o-graph.png)\n\nFuente: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nA continuación se muestra la lista de algunas de las notaciones de Big O más utilizadas y sus comparaciones de rendimiento\nfrente a diferentes tamaños de los datos de entrada.\n\n| Notación O grande | Cálculos para 10 elementos | Cálculos para 100 elementos | Cálculos para 1000 elementos |\n| ----------------- | -------------------------- | --------------------------- | ---------------------------- |\n| **O(1)**          | 1                          | 1                           | 1                            |\n| **O(log N)**      | 3                          | 6                           | 9                            |\n| **O(N)**          | 10                         | 100                         | 1000                         |\n| **O(N log N)**    | 30                         | 600                         | 9000                         |\n| **O(N^2)**        | 100                        | 10000                       | 1000000                      |\n| **O(2^N)**        | 1024                       | 1.26e+29                    | 1.07e+301                    |\n| **O(N!)**         | 3628800                    | 9.3e+157                    | 4.02e+2567                   |\n\n### Complejidad de las operaciones de estructuras de datos\n\n| Estructura de Datos            | Accesso | Busqueda | Inserción | Borrado | Comentarios                                                     |\n| ------------------------------ | :-----: | :------: | :-------: | :-----: | :-------------------------------------------------------------- |\n| **Colección**                  |    1    |    n     |     n     |    n    |                                                                 |\n| **Stack**                      |    n    |    n     |     1     |    1    |                                                                 |\n| **Cola**                       |    n    |    n     |     1     |    1    |                                                                 |\n| **Lista enlazada**             |    n    |    n     |     1     |    1    |                                                                 |\n| **Tabla hash**                 |    -    |    n     |     n     |    n    | En caso de función hash perfecta los costos serían O(1)         |\n| **Búsqueda por Árbol binario** |    n    |    n     |     n     |    n    | En el caso de un árbol equilibrado, los costos serían O(log(n)) |\n| **Árbol B**                    | log(n)  |  log(n)  |  log(n)   | log(n)  |                                                                 |\n| **Árbol Rojo-Negro**           | log(n)  |  log(n)  |  log(n)   | log(n)  |                                                                 |\n| **Árbol AVL**                  | log(n)  |  log(n)  |  log(n)   | log(n)  |                                                                 |\n| **Filtro de Bloom**            |    -    |    1     |     1     |    -    | Falsos positivos son posibles durante la búsqueda               |\n\n### Complejidad de algoritmos de ordenamiento de arreglos\n\n| Nombre                           | Mejor         | Promedio                | Pero                        | Memorya | Estable | Comentarios                                                   |\n| -------------------------------- | :-----------: | :---------------------: | :-------------------------: | :-----: | :-----: | :------------------------------------------------------------ |\n| **Ordenamiento de burbuja**      |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1     |  Si     |                                                               |\n| **Ordenamiento por inserción**   |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1     |  Si     |                                                               |\n| **Ordenamiento por selección**   | n<sup>2</sup> |      n<sup>2</sup>      |        n<sup>2</sup>        |   1     |   No    |                                                               |\n| **Ordenamiento por Heap**        | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   1     |   No    |                                                               |\n| **Ordenamiento por mezcla**      | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   n     |  Si     |                                                               |\n| **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         |\n| **Shellsort**                    | n&nbsp;log(n) | depende de la secuencia de huecos | n&nbsp;(log(n))<sup>2</sup> |   1   |   No   |                                                               |\n| **Ordenamiento por cuentas**     |     n + r     |          n + r          |            n + r            | n + r   |  Si     | r - mayor número en el arreglo                                |\n| **Ordenamiento Radix**           |    n \\* k     |         n \\* k          |           n \\* k            | n + k   |  Si     | k - largo de la llave más larga                                     |\n\n> ℹ️ Algunos otros [proyectos](https://trekhleb.dev/projects/) y [artículos](https://trekhleb.dev/blog/) sobre JavaScript y algoritmos en [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.fr-FR.md",
    "content": "# Algorithmes et Structures de Données en JavaScript\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nCe dépôt contient des exemples d'implémentation en JavaScript de plusieurs\nalgorithmes et structures de données populaires.\n\nChaque algorithme et structure de donnée possède son propre README contenant\nles explications détaillées et liens (incluant aussi des vidéos Youtube) pour\ncomplément d'informations.\n\n_Lisez ceci dans d'autres langues:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Data Structures\n\nUne structure de données est une manière spéciale d'organiser et de stocker\ndes données dans un ordinateur de manière à ce que l'on puisse accéder à\ncette information et la modifier de manière efficiente. De manière plus\nspécifique, une structure de données est un ensemble composé d'une collection\nde valeurs, des relations entre ces valeurs ainsi que d'un ensemble de\nfonctions ou d'opérations pouvant être appliquées sur ces données.\n\n`B` - Débutant, `A` - Avancé\n\n- `B` [Liste Chaînée](src/data-structures/linked-list)\n- `B` [Liste Doublement Chaînée](src/data-structures/doubly-linked-list)\n- `B` [Queue](src/data-structures/queue)\n- `B` [Pile](src/data-structures/stack)\n- `B` [Table de Hachage](src/data-structures/hash-table)\n- `B` [Tas](src/data-structures/heap)\n- `B` [Queue de Priorité](src/data-structures/priority-queue)\n- `A` [Trie](src/data-structures/trie)\n- `A` [Arbre](src/data-structures/tree)\n  - `A` [Arbre de recherche Binaire](src/data-structures/tree/binary-search-tree)\n  - `A` [Arbre AVL](src/data-structures/tree/avl-tree)\n  - `A` [Arbre Red-Black](src/data-structures/tree/red-black-tree)\n  - `A` [Arbre de Segments](src/data-structures/tree/segment-tree) - avec exemples de requêtes de type min/max/somme sur intervalles\n  - `A` [Arbre de Fenwick](src/data-structures/tree/fenwick-tree) (Arbre Binaire Indexé)\n- `A` [Graphe](src/data-structures/graph) (orienté et non orienté)\n- `A` [Ensembles Disjoints](src/data-structures/disjoint-set)\n- `A` [Filtre de Bloom](src/data-structures/bloom-filter)\n\n## Algorithmes\n\nUn algorithme est une démarche non ambigüe expliquant comment résoudre une\nclasse de problèmes. C'est un ensemble de règles décrivant de manière précise\nune séquence d'opérations.\n\n`B` - Débutant, `A` - Avancé\n\n### Algorithmes par topic\n\n- **Math**\n  - `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.\n  - `B` [Factorielle](src/algorithms/math/factorial/README.fr-FR.md)\n  - `B` [Nombre de Fibonacci](src/algorithms/math/fibonacci/README.fr-FR.md)\n  - `B` [Test de Primalité](src/algorithms/math/primality-test) (méthode du test de division)\n  - `B` [Algorithme d'Euclide](src/algorithms/math/euclidean-algorithm/README.fr-FR.md) - calcule le Plus Grand Commun Diviseur (PGCD)\n  - `B` [Plus Petit Commun Multiple](src/algorithms/math/least-common-multiple) (PPCM)\n  - `B` [Crible d'Eratosthène](src/algorithms/math/sieve-of-eratosthenes) - trouve tous les nombres premiers inférieurs à une certaine limite\n  - `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)\n  - `B` [Triangle de Pascal](src/algorithms/math/pascal-triangle)\n  - `B` [Nombre complexe](src/algorithms/math/complex-number/README.fr-FR.md) - nombres complexes et opérations de bases\n  - `A` [Partition Entière](src/algorithms/math/integer-partition)\n  - `A` [Approximation de π par l'algorithme de Liu Hui](src/algorithms/math/liu-hui) - approximation du calcul de π basé sur les N-gons\n  - `B` [Exponentiation rapide](src/algorithms/math/fast-powering/README.fr-FR.md)\n  - `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\n- **Ensembles**\n  - `B` [Produit Cartésien](src/algorithms/sets/cartesian-product) - produit de plusieurs ensembles\n  - `B` [Mélange de Fisher–Yates](src/algorithms/sets/fisher-yates) - permulation aléatoire d'une séquence finie\n  - `A` [Ensemble des parties d'un ensemble](src/algorithms/sets/power-set) - tous les sous-ensembles d'un ensemble\n  - `A` [Permutations](src/algorithms/sets/permutations) (avec et sans répétitions)\n  - `A` [Combinaisons](src/algorithms/sets/combinations) (avec et sans répétitions)\n  - `A` [Plus Longue Sous-séquence Commune](src/algorithms/sets/longest-common-subsequence)\n  - `A` [Plus Longue Sous-suite strictement croissante](src/algorithms/sets/longest-increasing-subsequence)\n  - `A` [Plus Courte Super-séquence Commune](src/algorithms/sets/shortest-common-supersequence)\n  - `A` [Problème du Sac à Dos](src/algorithms/sets/knapsack-problem) - versions \"0/1\" et \"Sans Contraintes\"\n  - `A` [Sous-partie Maximum](src/algorithms/sets/maximum-subarray) - versions \"Force Brute\" et \"Programmation Dynamique\" (Kadane)\n  - `A` [Somme combinatoire](src/algorithms/sets/combination-sum) - trouve toutes les combinaisons qui forment une somme spécifique\n- **Chaînes de Caractères**\n  - `B` [Distance de Hamming](src/algorithms/string/hamming-distance) - nombre de positions auxquelles les symboles sont différents\n  - `A` [Distance de Levenshtein](src/algorithms/string/levenshtein-distance) - distance minimale d'édition entre deux séquences\n  - `A` [Algorithme de Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (Algorithme KMP) - recherche de sous-chaîne (pattern matching)\n  - `A` [Algorithme Z](src/algorithms/string/z-algorithm) - recherche de sous-chaîne (pattern matching)\n  - `A` [Algorithme de Rabin Karp](src/algorithms/string/rabin-karp) - recherche de sous-chaîne\n  - `A` [Plus Longue Sous-chaîne Commune](src/algorithms/string/longest-common-substring)\n  - `A` [Expression Régulière](src/algorithms/string/regular-expression-matching)\n- **Recherche**\n  - `B` [Recherche Linéaire](src/algorithms/search/linear-search)\n  - `B` [Jump Search](src/algorithms/search/jump-search) Recherche par saut (ou par bloc) - recherche dans une liste triée\n  - `B` [Recherche Binaire](src/algorithms/search/binary-search) - recherche dans une liste triée\n  - `B` [Recherche par Interpolation](src/algorithms/search/interpolation-search) - recherche dans une liste triée et uniformément distribuée\n- **Tri**\n  - `B` [Tri Bullet](src/algorithms/sorting/bubble-sort)\n  - `B` [Tri Sélection](src/algorithms/sorting/selection-sort)\n  - `B` [Tri Insertion](src/algorithms/sorting/insertion-sort)\n  - `B` [Tri Par Tas](src/algorithms/sorting/heap-sort)\n  - `B` [Tri Fusion](src/algorithms/sorting/merge-sort)\n  - `B` [Tri Rapide](src/algorithms/sorting/quick-sort) - implémentations _in-place_ et _non in-place_\n  - `B` [Tri Shell](src/algorithms/sorting/shell-sort)\n  - `B` [Tri Comptage](src/algorithms/sorting/counting-sort)\n  - `B` [Tri Radix](src/algorithms/sorting/radix-sort)\n- **Arbres**\n  - `B` [Parcours en Profondeur](src/algorithms/tree/depth-first-search) (DFS)\n  - `B` [Parcours en Largeur](src/algorithms/tree/breadth-first-search) (BFS)\n- **Graphes**\n  - `B` [Parcours en Profondeur](src/algorithms/graph/depth-first-search) (DFS)\n  - `B` [Parcours en Largeur](src/algorithms/graph/breadth-first-search) (BFS)\n  - `B` [Algorithme de Kruskal](src/algorithms/graph/kruskal) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé\n  - `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\n  - `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\n  - `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\n  - `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)\n  - `A` [Algorithme de Prim](src/algorithms/graph/prim) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé\n  - `A` [Tri Topologique](src/algorithms/graph/topological-sorting) - méthode DFS\n  - `A` [Point d'Articulation](src/algorithms/graph/articulation-points) - algorithme de Tarjan (basé sur l'algorithme de Parcours en Profondeur)\n  - `A` [Bridges](src/algorithms/graph/bridges) - algorithme basé sur le Parcours en Profondeur\n  - `A` [Chemin Eulérien et Circuit Eulérien](src/algorithms/graph/eulerian-path) - algorithme de Fleury - visite chaque arc exactement une fois\n  - `A` [Cycle Hamiltonien](src/algorithms/graph/hamiltonian-cycle) - visite chaque noeud exactement une fois\n  - `A` [Composants Fortements Connexes](src/algorithms/graph/strongly-connected-components) - algorithme de Kosaraju\n  - `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\n- **Non catégorisé**\n  - `B` [Tours de Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  - `B` [Rotation de Matrice Carrée](src/algorithms/uncategorized/square-matrix-rotation) - algorithme _in place_\n  - `B` [Jump Game](src/algorithms/uncategorized/jump-game) - retour sur trace, programmation dynamique (haut-bas + bas-haut) et exemples gourmands\n  - `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\n  - `A` [Problème des N-Dames](src/algorithms/uncategorized/n-queens)\n  - `A` [Problème du Cavalier](src/algorithms/uncategorized/knight-tour)\n\n### Algorithmes par Paradigme\n\nUn paradigme algorithmique est une méthode générique ou une approche qui\nsous-tend la conception d'une classe d'algorithmes. C'est une abstraction\nau-dessus de la notion d'algorithme, tout comme l'algorithme est une abstraction\nsupérieure à un programme informatique.\n\n- **Force Brute** - cherche parmi toutes les possibilités et retient la meilleure\n  - `B` [Recherche Linéaire](src/algorithms/search/linear-search)\n  - `A` [Sous-partie Maximum](src/algorithms/sets/maximum-subarray)\n  - `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\n- **Gourmand** - choisit la meilleure option à l'instant courant, sans tenir compte de la situation future\n  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  - `A` [Problème du Sac à Dos Sans Contraintes](src/algorithms/sets/knapsack-problem)\n  - `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\n  - `A` [Algorithme de Prim](src/algorithms/graph/prim) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé\n  - `A` [Algorithme de Kruskal](src/algorithms/graph/kruskal) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé\n- **Diviser et Régner** - divise le problème en sous problèmes (plus simples) et résoud ces sous problèmes\n  - `B` [Recherche Binaire](src/algorithms/search/binary-search)\n  - `B` [Tours de Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  - `B` [Triangle de Pascal](src/algorithms/math/pascal-triangle)\n  - `B` [Algorithme d'Euclide](src/algorithms/math/euclidean-algorithm) - calcule le Plus Grand Commun Diviseur (PGCD)\n  - `B` [Tri Fusion](src/algorithms/sorting/merge-sort)\n  - `B` [Tri Rapide](src/algorithms/sorting/quick-sort)\n  - `B` [Arbre de Parcours en Profondeur](src/algorithms/tree/depth-first-search) (DFS)\n  - `B` [Graphe de Parcours en Profondeur](src/algorithms/graph/depth-first-search) (DFS)\n  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  - `A` [Permutations](src/algorithms/sets/permutations) (avec et sans répétitions)\n  - `A` [Combinations](src/algorithms/sets/combinations) (avec et sans répétitions)\n- **Programmation Dynamique** - construit une solution en utilisant les solutions précédemment trouvées\n  - `B` [Nombre de Fibonacci](src/algorithms/math/fibonacci)\n  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  - `B` [Chemins Uniques](src/algorithms/uncategorized/unique-paths)\n  - `A` [Distance de Levenshtein](src/algorithms/string/levenshtein-distance) - distance minimale d'édition entre deux séquences\n  - `A` [Plus Longue Sous-séquence Commune](src/algorithms/sets/longest-common-subsequence)\n  - `A` [Plus Longue Sous-chaîne Commune](src/algorithms/string/longest-common-substring)\n  - `A` [Plus Longue Sous-suite strictement croissante](src/algorithms/sets/longest-increasing-subsequence)\n  - `A` [Plus Courte Super-séquence Commune](src/algorithms/sets/shortest-common-supersequence)\n  - `A` [Problème de Sac à Dos](src/algorithms/sets/knapsack-problem)\n  - `A` [Partition Entière](src/algorithms/math/integer-partition)\n  - `A` [Sous-partie Maximum](src/algorithms/sets/maximum-subarray)\n  - `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\n  - `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\n  - `A` [Expression Régulière](src/algorithms/string/regular-expression-matching)\n- **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\n  chemin différent pour tester d'autres solutions. Normalement, la traversée en profondeur de l'espace d'états est utilisée.\n  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  - `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  - `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once\n  - `A` [Problème des N-Dames](src/algorithms/uncategorized/n-queens)\n  - `A` [Problème du Cavalier](src/algorithms/uncategorized/knight-tour)\n  - `A` [Somme combinatoire](src/algorithms/sets/combination-sum) - trouve toutes les combinaisons qui forment une somme spécifique\n- **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.\n\n## Comment utiliser ce dépôt\n\n**Installer toutes les dépendances**\n\n```\nnpm install\n```\n\n**Exécuter ESLint**\n\nVous pouvez l'installer pour tester la qualité du code.\n\n```\nnpm run lint\n```\n\n**Exécuter tous les tests**\n\n```\nnpm test\n```\n\n**Exécuter les tests par nom**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**Tests personnalisés**\n\nVous pouvez manipuler les structures de données et algorithmes présents dans ce\ndépôt avec le fichier `./src/playground/playground.js` et écrire vos propres\ntests dans file `./src/playground/__test__/playground.test.js`.\n\nVous pourrez alors simplement exécuter la commande suivante afin de tester si\nvotre code fonctionne comme escompté\n\n```\nnpm test -- 'playground'\n```\n\n## Informations Utiles\n\n### Références\n\n[▶ Structures de Données et Algorithmes sur YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Notation Grand O\n\nComparaison de la performance d'algorithmes en notation Grand O.\n\n![Big O graphs](./assets/big-o-graph.png)\n\nSource: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nVoici la liste de certaines des notations Grand O les plus utilisées et de leurs\ncomparaisons de performance suivant différentes tailles pour les données d'entrée.\n\n| Notation Grand O | Opérations pour 10 éléments | Opérations pour 100 éléments | Opérations pour 1000 éléments |\n| ---------------- | --------------------------- | ---------------------------- | ----------------------------- |\n| **O(1)**         | 1                           | 1                            | 1                             |\n| **O(log N)**     | 3                           | 6                            | 9                             |\n| **O(N)**         | 10                          | 100                          | 1000                          |\n| **O(N log N)**   | 30                          | 600                          | 9000                          |\n| **O(N^2)**       | 100                         | 10000                        | 1000000                       |\n| **O(2^N)**       | 1024                        | 1.26e+29                     | 1.07e+301                     |\n| **O(N!)**        | 3628800                     | 9.3e+157                     | 4.02e+2567                    |\n\n### Complexité des Opérations suivant les Structures de Données\n\n| Structure de donnée            | Accès  | Recherche | Insertion | Suppression | Commentaires                                                               |\n| ------------------------------ | :----: | :-------: | :-------: | :---------: | :------------------------------------------------------------------------- |\n| **Liste**                      |   1    |     n     |     n     |      n      |                                                                            |\n| **Pile**                       |   n    |     n     |     1     |      1      |                                                                            |\n| **Queue**                      |   n    |     n     |     1     |      1      |                                                                            |\n| **Liste Liée**                 |   n    |     n     |     1     |      1      |                                                                            |\n| **Table de Hachage**           |   -    |     n     |     n     |      n      | Dans le cas des fonctions de hachage parfaites, les couts seraient de O(1) |\n| **Arbre de Recherche Binaire** |   n    |     n     |     n     |      n      | Dans le cas des arbre équilibrés, les coûts seraient de O(log(n))          |\n| **Arbre B**                    | log(n) |  log(n)   |  log(n)   |   log(n)    |                                                                            |\n| **Arbre Red-Black**            | log(n) |  log(n)   |  log(n)   |   log(n)    |                                                                            |\n| **Arbre AVL**                  | log(n) |  log(n)   |  log(n)   |   log(n)    |                                                                            |\n| **Filtre de Bloom**            |   -    |     1     |     1     |      -      | Les faux positifs sont possibles lors de la recherche                      |\n\n### Complexité des Algorithmes de Tri de Liste\n\n| Nom               |   Meilleur    |        Moyenne         |            Pire             | Mémoire | Stable | Commentaires                                                                         |\n| ----------------- | :-----------: | :--------------------: | :-------------------------: | :-----: | :----: | :----------------------------------------------------------------------------------- |\n| **Tri Bulle**     |       n       |     n<sup>2</sup>      |        n<sup>2</sup>        |    1    |  Oui   |                                                                                      |\n| **Tri Insertion** |       n       |     n<sup>2</sup>      |        n<sup>2</sup>        |    1    |  Oui   |                                                                                      |\n| **Tri Sélection** | n<sup>2</sup> |     n<sup>2</sup>      |        n<sup>2</sup>        |    1    |  Non   |                                                                                      |\n| **Tri par Tas**   | n&nbsp;log(n) |     n&nbsp;log(n)      |        n&nbsp;log(n)        |    1    |  Non   |                                                                                      |\n| **Merge sort**    | n&nbsp;log(n) |     n&nbsp;log(n)      |        n&nbsp;log(n)        |    n    |  Oui   |                                                                                      |\n| **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)) |\n| **Tri Shell**     | n&nbsp;log(n) | dépend du gap séquence | n&nbsp;(log(n))<sup>2</sup> |    1    |  Non   |                                                                                      |\n| **Tri Comptage**  |     n + r     |         n + r          |            n + r            |  n + r  |  Oui   | r - le plus grand nombre dans la liste                                               |\n| **Tri Radix**     |    n \\* k     |         n \\* k         |           n \\* k            |  n + k  |  Non   | k - longueur du plus long index                                                      |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.he-IL.md",
    "content": "# אלגוריתמים ומבני נתונים ב-JavaScript\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n![גודל המאגר](https://img.shields.io/github/repo-size/trekhleb/javascript-algorithms.svg)\n\nמאגר זה מכיל דוגמאות מבוססות JavaScript של אלגוריתמים ומבני נתונים פופולריים רבים.\n\nלכל אלגוריתם ומבנה נתונים יש README משלו עם הסברים קשורים וקישורים לקריאה נוספת (כולל קישורים לסרטוני YouTube).\n\n_קרא זאת בשפות אחרות:_\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türkçe_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n\n## מבני נתונים\n\nמבנה נתונים הוא דרך מסוימת לארגן ולאחסן נתונים במחשב כך שניתן לגשת אליהם ולשנות אותם ביעילות. ליתר דיוק, מבנה נתונים הוא אוסף של ערכי נתונים, היחסים ביניהם, והפונקציות או הפעולות שניתן ליישם על הנתונים.\n\nזכור שלכל מבנה נתונים יש את היתרונות והחסרונות שלו. חשוב לשים לב יותר לסיבה שבגללה אתה בוחר מבנה נתונים מסוים מאשר לאופן היישום שלו.\n\n`B` - מתחיל, `A` - מתקדם\n\n* `B` [רשימה מקושרת](src/data-structures/linked-list)\n* `B` [רשימה מקושרת כפולה](src/data-structures/doubly-linked-list)\n* `B` [תור](src/data-structures/queue)\n* `B` [מחסנית](src/data-structures/stack)\n* `B` [טבלת גיבוב](src/data-structures/hash-table)\n* `B` [ערימה](src/data-structures/heap) - גרסאות מקסימום ומינימום\n* `B` [תור עדיפויות](src/data-structures/priority-queue)\n* `A` [עץ תחיליות](src/data-structures/trie)\n* `A` [עץ](src/data-structures/tree)\n  * `A` [עץ חיפוש בינארי](src/data-structures/tree/binary-search-tree)\n  * `A` [עץ AVL](src/data-structures/tree/avl-tree)\n  * `A` [עץ אדום-שחור](src/data-structures/tree/red-black-tree)\n  * `A` [עץ מקטעים](src/data-structures/tree/segment-tree) - עם דוגמאות לשאילתות מינימום/מקסימום/סכום של טווח\n  * `A` [עץ פנוויק](src/data-structures/tree/fenwick-tree) (עץ בינארי מאונדקס)\n* `A` [גרף](src/data-structures/graph) (מכוון ולא מכוון)\n* `A` [קבוצה מופרדת](src/data-structures/disjoint-set) - מבנה נתונים של איחוד-מציאה או מיזוג-מציאה\n* `A` [מסנן בלום](src/data-structures/bloom-filter)\n* `A` [מטמון LRU](src/data-structures/lru-cache/) - מטמון פחות שימוש לאחרונה (LRU)\n\n## אלגוריתמים\n\nאלגוריתם הוא מפרט חד משמעי כיצד לפתור סוג של בעיות. זוהי קבוצה של כללים המגדירים במדויק רצף של פעולות.\n\n`B` - מתחיל, `A` - מתקדם\n\n### אלגוריתמים לפי נושא\n\n* **מתמטיקה**\n  * `B` [מניפולציה על ביטים](src/algorithms/math/bits) - קביעה/עדכון/ניקוי ביטים, הכפלה/חילוק ב-2, הפיכה לשלילי וכו'\n  * `B` [נקודה צפה בינארית](src/algorithms/math/binary-floating-point) - ייצוג בינארי של מספרים בנקודה צפה\n  * `B` [פקטוריאל](src/algorithms/math/factorial)\n  * `B` [מספר פיבונאצ'י](src/algorithms/math/fibonacci) - גרסאות קלאסיות וסגורות\n  * `B` [גורמים ראשוניים](src/algorithms/math/prime-factors) - מציאת גורמים ראשוניים וספירתם באמצעות משפט הארדי-רמנוג'אן\n  * `B` [בדיקת ראשוניות](src/algorithms/math/primality-test) (שיטת החלוקה הניסיונית)\n  * `B` [אלגוריתם אוקלידס](src/algorithms/math/euclidean-algorithm) - חישוב המחלק המשותף הגדול ביותר (GCD)\n  * `B` [המכפיל המשותף הקטן ביותר](src/algorithms/math/least-common-multiple) (LCM)\n  * `B` [נפה של ארטוסתנס](src/algorithms/math/sieve-of-eratosthenes) - מציאת כל המספרים הראשוניים עד לגבול כלשהו\n  * `B` [האם חזקה של שתיים](src/algorithms/math/is-power-of-two) - בדיקה אם מספר הוא חזקה של שתיים (אלגוריתמים נאיביים וביטיים)\n  * `B` [משולש פסקל](src/algorithms/math/pascal-triangle)\n  * `B` [מספר מרוכב](src/algorithms/math/complex-number) - מספרים מרוכבים ופעולות בסיסיות עליהם\n  * `B` [רדיאן ומעלות](src/algorithms/math/radian) - המרה מרדיאנים למעלות ובחזרה\n  * `B` [חזקה מהירה](src/algorithms/math/fast-powering)\n  * `B` [שיטת הורנר](src/algorithms/math/horner-method) - הערכת פולינום\n  * `B` [מטריצות](src/algorithms/math/matrix) - מטריצות ופעולות בסיסיות על מטריצות (כפל, טרנספוזיציה וכו')\n  * `B` [מרחק אוקלידי](src/algorithms/math/euclidean-distance) - מרחק בין שתי נקודות/וקטורים/מטריצות\n  * `A` [חלוקת מספר שלם](src/algorithms/math/integer-partition)\n  * `A` [שורש ריבועי](src/algorithms/math/square-root) - שיטת ניוטון\n  * `A` [אלגוריתם π של ליו הוי](src/algorithms/math/liu-hui) - חישובי π מקורבים על בסיס N-גונים\n  * `A` [התמרת פורייה הבדידה](src/algorithms/math/fourier-transform) - פירוק פונקציה של זמן (אות) לתדרים המרכיבים אותה\n\n* **קבוצות**\n  * `B` [מכפלה קרטזית](src/algorithms/sets/cartesian-product) - מכפלה של מספר קבוצות\n  * `B` [ערבוב פישר-ייטס](src/algorithms/sets/fisher-yates) - תמורה אקראית של רצף סופי\n  * `A` [קבוצת חזקה](src/algorithms/sets/power-set) - כל תתי הקבוצות של קבוצה (פתרונות ביטיים, מעקב לאחור וקסקדה)\n  * `A` [תמורות](src/algorithms/sets/permutations) (עם ובלי חזרות)\n  * `A` [צירופים](src/algorithms/sets/combinations) (עם ובלי חזרות)\n  * `A` [תת-רצף משותף ארוך ביותר](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [תת-רצף עולה ארוך ביותר](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [על-רצף משותף קצר ביותר](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [בעיית התרמיל](src/algorithms/sets/knapsack-problem) - \"0/1\" ו\"לא מוגבל\"\n  * `A` [תת-מערך מקסימלי](src/algorithms/sets/maximum-subarray) - \"כוח ברוטלי\" ו\"תכנות דינמי\" (Kadane) גרסאות\n  * `A` [סכום צירוף](src/algorithms/sets/combination-sum) - מציאת כל הצירופים שיוצרים סכום ספציפי\n\n* **מחרוזות**\n  * `B` [מרחק המינג](src/algorithms/string/hamming-distance) - מספר העמדות שבהן הסמלים שונים\n  * `B` [פלינדרום](src/algorithms/string/palindrome) - בדיקה אם המחרוזת זהה בקריאה לאחור\n  * `A` [מרחק לוונשטיין](src/algorithms/string/levenshtein-distance) - מרחק העריכה המינימלי בין שתי רצפים\n  * `A` [אלגוריתם קנות'-מוריס-פראט](src/algorithms/string/knuth-morris-pratt) (אלגוריתם KMP) - חיפוש תת-מחרוזת (התאמת תבנית)\n  * `A` [אלגוריתם Z](src/algorithms/string/z-algorithm) - חיפוש תת-מחרוזת (התאמת תבנית)\n  * `A` [אלגוריתם רבין קארפ](src/algorithms/string/rabin-karp) - חיפוש תת-מחרוזת\n  * `A` [תת-מחרוזת משותפת ארוכה ביותר](src/algorithms/string/longest-common-substring)\n  * `A` [התאמת ביטוי רגולרי](src/algorithms/string/regular-expression-matching)\n\n* **חיפושים**\n  * `B` [חיפוש לינארי](src/algorithms/search/linear-search)\n  * `B` [חיפוש קפיצות](src/algorithms/search/jump-search) (או חיפוש בלוקים) - חיפוש במערך ממוין\n  * `B` [חיפוש בינארי](src/algorithms/search/binary-search) - חיפוש במערך ממוין\n  * `B` [חיפוש אינטרפולציה](src/algorithms/search/interpolation-search) - חיפוש במערך ממוין עם התפלגות אחידה\n\n* **מיון**\n  * `B` [מיון בועות](src/algorithms/sorting/bubble-sort)\n  * `B` [מיון בחירה](src/algorithms/sorting/selection-sort)\n  * `B` [מיון הכנסה](src/algorithms/sorting/insertion-sort)\n  * `B` [מיון ערימה](src/algorithms/sorting/heap-sort)\n  * `B` [מיון מיזוג](src/algorithms/sorting/merge-sort)\n  * `B` [מיון מהיר](src/algorithms/sorting/quick-sort) - יישומים במקום ולא במקום\n  * `B` [מיון צדפות](src/algorithms/sorting/shell-sort)\n  * `B` [מיון ספירה](src/algorithms/sorting/counting-sort)\n  * `B` [מיון בסיס](src/algorithms/sorting/radix-sort)\n  * `B` [מיון דלי](src/algorithms/sorting/bucket-sort)\n\n* **רשימות מקושרות**\n  * `B` [מעבר ישר](src/algorithms/linked-list/traversal)\n  * `B` [מעבר הפוך](src/algorithms/linked-list/reverse-traversal)\n\n* **עצים**\n  * `B` [חיפוש לעומק](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [חיפוש לרוחב](src/algorithms/tree/breadth-first-search) (BFS)\n\n* **גרפים**\n  * `B` [חיפוש לעומק](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [חיפוש לרוחב](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [אלגוריתם קרוסקל](src/algorithms/graph/kruskal) - מציאת עץ פורש מינימלי (MST) עבור גרף לא מכוון משוקלל\n  * `A` [אלגוריתם דייקסטרה](src/algorithms/graph/dijkstra) - מציאת המסלולים הקצרים ביותר לכל קודקודי הגרף מקודקוד יחיד\n  * `A` [אלגוריתם בלמן-פורד](src/algorithms/graph/bellman-ford) - מציאת המסלולים הקצרים ביותר לכל קודקודי הגרף מקודקוד יחיד\n  * `A` [אלגוריתם פלויד-וורשל](src/algorithms/graph/floyd-warshall) - מציאת המסלולים הקצרים ביותר בין כל זוגות הקודקודים\n  * `A` [זיהוי מעגל](src/algorithms/graph/detect-cycle) - עבור גרפים מכוונים ולא מכוונים (גרסאות מבוססות DFS וקבוצה מופרדת)\n  * `A` [אלגוריתם פרים](src/algorithms/graph/prim) - מציאת עץ פורש מינימלי (MST) עבור גרף לא מכוון משוקלל\n  * `A` [מיון טופולוגי](src/algorithms/graph/topological-sorting) - שיטת DFS\n  * `A` [נקודות חיתוך](src/algorithms/graph/articulation-points) - אלגוריתם טרג'ן (מבוסס DFS)\n  * `A` [גשרים](src/algorithms/graph/bridges) - אלגוריתם מבוסס DFS\n  * `A` [מסלול ומעגל אוילר](src/algorithms/graph/eulerian-path) - אלגוריתם פלרי - ביקור בכל קשת בדיוק פעם אחת\n  * `A` [מעגל המילטון](src/algorithms/graph/hamiltonian-cycle) - ביקור בכל קודקוד בדיוק פעם אחת\n  * `A` [רכיבים קשירים חזק](src/algorithms/graph/strongly-connected-components) - אלגוריתם קוסרג'ו\n  * `A` [בעיית הסוכן הנוסע](src/algorithms/graph/travelling-salesman) - המסלול הקצר ביותר האפשרי שמבקר בכל עיר וחוזר לעיר המוצא\n\n* **הצפנה**\n  * `B` [גיבוב פולינומי](src/algorithms/cryptography/polynomial-hash) - פונקציית גיבוב מתגלגלת המבוססת על פולינום\n  * `B` [צופן גדר מסילה](src/algorithms/cryptography/rail-fence-cipher) - אלגוריתם הצפנת טרנספוזיציה להצפנת הודעות\n  * `B` [צופן קיסר](src/algorithms/cryptography/caesar-cipher) - צופן החלפה פשוט\n  * `B` [צופן היל](src/algorithms/cryptography/hill-cipher) - צופן החלפה המבוסס על אלגברה לינארית\n\n* **למידת מכונה**\n  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 פונקציות JS פשוטות שמדגימות כיצד מכונות יכולות ללמוד באמת (תפוצה קדימה/אחורה)\n  * `B` [k-NN](src/algorithms/ml/knn) - אלגוריתם סיווג k-השכנים הקרובים ביותר\n  * `B` [k-Means](src/algorithms/ml/k-means) - אלגוריתם אשכול k-Means\n\n* **עיבוד תמונה**\n  * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - אלגוריתם שינוי גודל תמונה מודע תוכן\n\n* **סטטיסטיקה**\n  * `B` [משקל אקראי](src/algorithms/statistics/weighted-random) - בחירת פריט אקראי מהרשימה על בסיס משקלי הפריטים\n\n* **אלגוריתמים אבולוציוניים**\n  * `A` [אלגוריתם גנטי](https://github.com/trekhleb/self-parking-car-evolution) - דוגמה לאופן שבו ניתן ליישם אלגוריתם גנטי לאימון מכוניות בחניה עצמית\n\n* **לא מסווג**\n  * `B` [מגדלי האנוי](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [סיבוב מטריצה ריבועית](src/algorithms/uncategorized/square-matrix-rotation) - אלגוריתם במקום\n  * `B` [משחק הקפיצות](src/algorithms/uncategorized/jump-game) - דוגמאות למעקב לאחור, תכנות דינמי (מלמעלה למטה + מלמטה למעלה) וחמדני\n  * `B` [מסלולים ייחודיים](src/algorithms/uncategorized/unique-paths) - דוגמאות למעקב לאחור, תכנות דינמי ומבוססות על משולש פסקל\n  * `B` [מדרגות גשם](src/algorithms/uncategorized/rain-terraces) - בעיית לכידת מי גשם (גרסאות תכנות דינמי וכוח ברוטלי)\n  * `B` [מדרגות רקורסיביות](src/algorithms/uncategorized/recursive-staircase) - ספירת מספר הדרכים להגיע לראש (4 פתרונות)\n  * `B` [הזמן הטוב ביותר לקנות ולמכור מניות](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - דוגמאות לחלוקה וכיבוש ומעבר אחד\n  * `A` [בעיית N-המלכות](src/algorithms/uncategorized/n-queens)\n  * `A` [סיור הפרש](src/algorithms/uncategorized/knight-tour)\n\n### אלגוריתמים לפי פרדיגמה\n\nפרדיגמה אלגוריתמית היא שיטה או גישה כללית המונחת בבסיס התכנון של מחלקת אלגוריתמים. זוהי הפשטה גבוהה יותר מהמושג של אלגוריתם, בדיוק כפי שאלגוריתם הוא הפשטה גבוהה יותר מתוכנית מחשב.\n\n* **כוח ברוטלי** - בודק את כל האפשרויות ובוחר את הפתרון הטוב ביותר\n  * `B` [חיפוש לינארי](src/algorithms/search/linear-search)\n  * `B` [מדרגות גשם](src/algorithms/uncategorized/rain-terraces) - בעיית לכידת מי גשם\n  * `B` [מדרגות רקורסיביות](src/algorithms/uncategorized/recursive-staircase) - ספירת מספר הדרכים להגיע לראש\n  * `A` [תת-מערך מקסימלי](src/algorithms/sets/maximum-subarray)\n  * `A` [בעיית הסוכן הנוסע](src/algorithms/graph/travelling-salesman) - המסלול הקצר ביותר האפשרי שמבקר בכל עיר וחוזר לעיר המוצא\n  * `A` [התמרת פורייה הבדידה](src/algorithms/math/fourier-transform) - פירוק פונקציה של זמן (אות) לתדרים המרכיבים אותה\n\n* **חמדני** - בוחר את האפשרות הטובה ביותר בזמן הנוכחי, ללא כל התחשבות בעתיד\n  * `B` [משחק הקפיצות](src/algorithms/uncategorized/jump-game)\n  * `A` [בעיית התרמיל הלא מוגבל](src/algorithms/sets/knapsack-problem)\n  * `A` [אלגוריתם דייקסטרה](src/algorithms/graph/dijkstra) - מציאת המסלולים הקצרים ביותר לכל קודקודי הגרף\n  * `A` [אלגוריתם פרים](src/algorithms/graph/prim) - מציאת עץ פורש מינימלי (MST) עבור גרף לא מכוון משוקלל\n  * `A` [אלגוריתם קרוסקל](src/algorithms/graph/kruskal) - מציאת עץ פורש מינימלי (MST) עבור גרף לא מכוון משוקלל\n\n* **חלוקה וכיבוש** - מחלק את הבעיה לחלקים קטנים יותר ואז פותר חלקים אלה\n  * `B` [חיפוש בינארי](src/algorithms/search/binary-search)\n  * `B` [מגדלי האנוי](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [משולש פסקל](src/algorithms/math/pascal-triangle)\n  * `B` [אלגוריתם אוקלידס](src/algorithms/math/euclidean-algorithm) - חישוב המחלק המשותף הגדול ביותר (GCD)\n  * `B` [מיון מיזוג](src/algorithms/sorting/merge-sort)\n  * `B` [מיון מהיר](src/algorithms/sorting/quick-sort)\n  * `B` [חיפוש לעומק בעץ](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [חיפוש לעומק בגרף](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [מטריצות](src/algorithms/math/matrix) - יצירה ומעבר על מטריצות בצורות שונות\n  * `B` [משחק הקפיצות](src/algorithms/uncategorized/jump-game)\n  * `B` [חזקה מהירה](src/algorithms/math/fast-powering)\n  * `B` [הזמן הטוב ביותר לקנות ולמכור מניות](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - דוגמאות לחלוקה וכיבוש ומעבר אחד\n  * `A` [תמורות](src/algorithms/sets/permutations) (עם ובלי חזרות)\n  * `A` [צירופים](src/algorithms/sets/combinations) (עם ובלי חזרות)\n  * `A` [תת-מערך מקסימלי](src/algorithms/sets/maximum-subarray)\n\n* **תכנות דינמי** - בניית פתרון באמצעות תת-פתרונות שנמצאו קודם לכן\n  * `B` [מספר פיבונאצ'י](src/algorithms/math/fibonacci)\n  * `B` [משחק הקפיצות](src/algorithms/uncategorized/jump-game)\n  * `B` [מסלולים ייחודיים](src/algorithms/uncategorized/unique-paths)\n  * `B` [מדרגות גשם](src/algorithms/uncategorized/rain-terraces) - בעיית לכידת מי גשם\n  * `B` [מדרגות רקורסיביות](src/algorithms/uncategorized/recursive-staircase) - ספירת מספר הדרכים להגיע לראש\n  * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - אלגוריתם שינוי גודל תמונה מודע תוכן\n  * `A` [מרחק לוונשטיין](src/algorithms/string/levenshtein-distance) - מרחק העריכה המינימלי בין שתי רצפים\n  * `A` [תת-רצף משותף ארוך ביותר](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [תת-מחרוזת משותפת ארוכה ביותר](src/algorithms/string/longest-common-substring)\n  * `A` [תת-רצף עולה ארוך ביותר](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [על-רצף משותף קצר ביותר](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [בעיית התרמיל 0/1](src/algorithms/sets/knapsack-problem)\n  * `A` [חלוקת מספר שלם](src/algorithms/math/integer-partition)\n  * `A` [תת-מערך מקסימלי](src/algorithms/sets/maximum-subarray)\n  * `A` [אלגוריתם בלמן-פורד](src/algorithms/graph/bellman-ford) - מציאת המסלולים הקצרים ביותר לכל קודקודי הגרף\n  * `A` [אלגוריתם פלויד-וורשל](src/algorithms/graph/floyd-warshall) - מציאת המסלולים הקצרים ביותר בין כל זוגות הקודקודים\n  * `A` [התאמת ביטוי רגולרי](src/algorithms/string/regular-expression-matching)\n\n* **מעקב לאחור** - בדומה לכוח ברוטלי, מנסה לייצר את כל הפתרונות האפשריים, אך בכל פעם שאתה מייצר פתרון הבא אתה בודק אם הוא עומד בכל התנאים, ורק אז ממשיך לייצר פתרונות הבאים. אחרת, חוזר אחורה, והולך בנתיב אחר של מציאת פתרון. בדרך כלל מעבר DFS של מרחב המצבים משמש.\n  * `B` [משחק הקפיצות](src/algorithms/uncategorized/jump-game)\n  * `B` [מסלולים ייחודיים](src/algorithms/uncategorized/unique-paths)\n  * `B` [קבוצת חזקה](src/algorithms/sets/power-set) - כל תתי הקבוצות של קבוצה\n  * `A` [מעגל המילטון](src/algorithms/graph/hamiltonian-cycle) - ביקור בכל קודקוד בדיוק פעם אחת\n  * `A` [בעיית N-המלכות](src/algorithms/uncategorized/n-queens)\n  * `A` [סיור הפרש](src/algorithms/uncategorized/knight-tour)\n  * `A` [סכום צירוף](src/algorithms/sets/combination-sum) - מציאת כל הצירופים שיוצרים סכום ספציפי\n\n* **סניף וחסום** - זוכר את הפתרון בעלות הנמוכה ביותר שנמצא בכל שלב של החיפוש המעקב לאחור, ומשתמש בעלות של הפתרון בעלות הנמוכה ביותר שנמצא עד כה כגבול תחתון על העלות של פתרון בעלות מינימלית לבעיה, על מנת לפסול פתרונות חלקיים עם עלויות גדולות יותר מהפתרון בעלות הנמוכה ביותר שנמצא עד כה. בדרך כלל מעבר BFS בשילוב עם מעבר DFS של עץ מרחב המצבים משמש.\n\n## כיצד להשתמש במאגר זה\n\n**התקנת כל התלויות**\n\n```\nnpm install\n```\n\n**הרצת ESLint**\n\nייתכן שתרצה להריץ אותו כדי לבדוק את איכות הקוד.\n\n```\nnpm run lint\n```\n\n**הרצת כל הבדיקות**\n\n```\nnpm test\n```\n\n**הרצת בדיקות לפי שם**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**פתרון בעיות**\n\nאם הלינטינג או הבדיקות נכשלים, נסה למחוק את התיקייה `node_modules` ולהתקין מחדש את חבילות npm:\n\n```\nrm -rf ./node_modules\nnpm i\n```\n\nבנוסף, ודא שאתה משתמש בגרסת Node נכונה (`>=16`). אם אתה משתמש ב-[nvm](https://github.com/nvm-sh/nvm) לניהול גרסאות Node, תוכל להריץ `nvm use` מתיקיית השורש של הפרויקט והגרסה הנכונה תיבחר.\n\n**שטח משחקים**\n\nאתה יכול לשחק עם מבני נתונים ואלגוריתמים בקובץ `./src/playground/playground.js` ולכתוב\nבדיקות עבורו ב-`./src/playground/__test__/playground.test.js`.\n\nלאחר מכן פשוט הרץ את הפקודה הבאה כדי לבדוק אם קוד שטח המשחקים שלך עובד כמצופה:\n\n```\nnpm test -- 'playground'\n```\n\n## מידע שימושי\n\n### הפניות\n\n- [▶ מבני נתונים ואלגוריתמים ב-YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [✍🏻 סקיצות של מבני נתונים](https://okso.app/showcase/data-structures)\n\n### סימון ה-O הגדול\n\nסימון *ה-O הגדול* משמש לסיווג אלגוריתמים לפי כיצד זמן הריצה או דרישות המרחב שלהם גדלים ככל שגודל הקלט גדל.\nבתרשים שלהלן תוכל למצוא את הסדרים הנפוצים ביותר של צמיחת אלגוריתמים המצוינים בסימון ה-O הגדול.\n\n![גרפי ה-O הגדול](./assets/big-o-graph.png)\n\nמקור: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nלהלן רשימה של כמה מסימוני ה-O הגדול הנפוצים ביותר והשוואות הביצועים שלהם מול גדלים שונים של נתוני קלט.\n\n| סימון ה-O הגדול | חישובים ל-10 אלמנטים | חישובים ל-100 אלמנטים | חישובים ל-1000 אלמנטים |\n| ---------------- | --------------------- | ---------------------- | ----------------------- |\n| **O(1)**         | 1                     | 1                      | 1                       |\n| **O(log N)**     | 3                     | 6                      | 9                       |\n| **O(N)**         | 10                    | 100                    | 1000                    |\n| **O(N log N)**   | 30                    | 600                    | 9000                    |\n| **O(N^2)**       | 100                   | 10000                  | 1000000                 |\n| **O(2^N)**       | 1024                  | 1.26e+29               | 1.07e+301               |\n| **O(N!)**        | 3628800               | 9.3e+157               | 4.02e+2567              |\n\n### מורכבות פעולות מבני נתונים\n\n| מבנה נתונים          | גישה    | חיפוש   | הכנסה   | מחיקה   | הערות  |\n| --------------------- | :-----: | :-----: | :-----: | :-----: | :------ |\n| **מערך**              | 1       | n       | n       | n       |         |\n| **מחסנית**            | n       | n       | 1       | 1       |         |\n| **תור**               | n       | n       | 1       | 1       |         |\n| **רשימה מקושרת**      | n       | n       | 1       | n       |         |\n| **טבלת גיבוב**        | -       | n       | n       | n       | במקרה של פונקציית גיבוב מושלמת, העלויות יהיו O(1) |\n| **עץ חיפוש בינארי**   | n       | n       | n       | n       | במקרה של עץ מאוזן, העלויות יהיו O(log(n)) |\n| **עץ B**              | log(n)  | log(n)  | log(n)  | log(n)  |         |\n| **עץ אדום-שחור**      | log(n)  | log(n)  | log(n)  | log(n)  |         |\n| **עץ AVL**            | log(n)  | log(n)  | log(n)  | log(n)  |         |\n| **מסנן בלום**         | -       | 1       | 1       | -       | תוצאות חיוביות שגויות אפשריות בעת חיפוש |\n\n### מורכבות אלגוריתמי מיון מערכים\n\n| שם                  | הטוב ביותר        | ממוצע               | הגרוע ביותר         | זיכרון  | יציב    | הערות  |\n| ------------------- | :----------------: | :-----------------: | :------------------: | :-----: | :-----: | :------ |\n| **מיון בועות**      | n                  | n<sup>2</sup>       | n<sup>2</sup>        | 1       | כן      |         |\n| **מיון הכנסה**      | n                  | n<sup>2</sup>       | n<sup>2</sup>        | 1       | כן      |         |\n| **מיון בחירה**      | n<sup>2</sup>      | n<sup>2</sup>       | n<sup>2</sup>        | 1       | לא      |         |\n| **מיון ערימה**      | n&nbsp;log(n)      | n&nbsp;log(n)       | n&nbsp;log(n)        | 1       | לא      |         |\n| **מיון מיזוג**      | n&nbsp;log(n)      | n&nbsp;log(n)       | n&nbsp;log(n)        | n       | כן      |         |\n| **מיון מהיר**       | n&nbsp;log(n)      | n&nbsp;log(n)       | n<sup>2</sup>        | log(n)  | לא      | מיון מהיר בדרך כלל מבוצע במקום עם O(log(n)) שטח מחסנית |\n| **מיון צדפות**      | n&nbsp;log(n)      | תלוי ברצף הפער      | n&nbsp;(log(n))<sup>2</sup>  | 1         | לא      |         |\n| **מיון ספירה**      | n + r              | n + r               | n + r                | n + r   | כן      | r - המספר הגדול ביותר במערך |\n| **מיון בסיס**       | n * k              | n * k               | n * k                | n + k   | כן      | k - אורך המפתח הארוך ביותר |\n\n## תומכי הפרויקט\n\n> אתה יכול לתמוך בפרויקט זה דרך ❤️️ [GitHub](https://github.com/sponsors/trekhleb) או ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n[אנשים שתומכים בפרויקט זה](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`\n\n## מחבר\n\n[@trekhleb](https://trekhleb.dev)\n\nכמה [פרויקטים](https://trekhleb.dev/projects/) ו[מאמרים](https://trekhleb.dev/blog/) נוספים על JavaScript ואלגוריתמים ב-[trekhleb.dev](https://trekhleb.dev)* `B` [משחק הקפיצות](src/algorithms/uncategor * `B` [חיפוש בינארי](src/algorithms\n"
  },
  {
    "path": "README.id-ID.md",
    "content": "# Algoritme dan Struktur Data Javascript\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nRepositori ini berisi contoh-contoh algoritme dan struktur data yang populer menggunakan JavaScript.\n\nSetiap algoritma dan struktur data memiliki README-nya tersendiri dengan penjelasan yang berkaitan dan tautan untuk bacaan lebih lanjut (termasuk tautan menuju video YouTube).\n\n_Baca ini dalam bahasa yang lain:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Struktur Data\n\nStruktur 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.\n\n`P` - Pemula, `L` - Lanjutan\n\n- `P` [Senarai Berantai](src/data-structures/linked-list)\n- `P` [Senarai Berantai Ganda](src/data-structures/doubly-linked-list)\n- `P` [Antrean](src/data-structures/queue)\n- `P` [Tumpukan](src/data-structures/stack)\n- `P` [Tabel Hash](src/data-structures/hash-table)\n- `P` [_Heap_](src/data-structures/heap) - versi _heap_ maksimum dan minimum\n- `P` [Antrean Prioritas](src/data-structures/priority-queue)\n- `L` [_Trie_](src/data-structures/trie)\n- `L` [Pohon](src/data-structures/tree)\n  - `L` [Pohon Telusur Biner](src/data-structures/tree/binary-search-tree)\n  - `L` [_AVL Tree_](src/data-structures/tree/avl-tree)\n  - `L` [Pohon Merah Hitam](src/data-structures/tree/red-black-tree)\n  - `L` [_Segment Tree_](src/data-structures/tree/segment-tree) - dengan contoh min/max/sum range query\n  - `L` [Pohon Fenwick](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)\n- `L` [Graf](src/data-structures/graph) (directed dan undirected)\n- `L` [_Disjoint Set_](src/data-structures/disjoint-set)\n- `L` [_Bloom Filter_](src/data-structures/bloom-filter)\n\n## Algoritma\n\nAlgoritma adalah sebuah perincian yang jelas tentang cara untuk memecahkan suatu masalah. Ia adalah sekumpulan aturan yang menjelaskan secara tepat urutan-urutan dari sebuah operasi.\n\n`P` - Pemula, `L` - Lanjutan\n\n### Algoritma Berdasarkanan Topik\n\n- **Matematika**\n  - `P` [Manipulasi Bit](src/algorithms/math/bits) - menetapkan/mendapatkan/memperbarui/menghapus bit, perkalian/pembagian dengan angka 2, membuat bilangan negatif dan lain-lain.\n  - `P` [Faktorial](src/algorithms/math/Faktorial)\n  - `P` [Bilangan Fibonacci](src/algorithms/math/fibonacci) - versi klasik dan bentuk tertutup\n  - `P` [Faktor Prima](src/algorithms/math/prime-factors) - menemukan faktor prima dan menghitungnya menggunakan teorema Hardy-Ramanujan\n  - `P` [Pengujian Bilangan Prima](src/algorithms/math/primality-test) (metode _trial division_)\n  - `P` [Algoritma Euclidean](src/algorithms/math/euclidean-algorithm) - menghitung Faktor Persekutuan Terbesar (FPB)\n  - `P` [_Least Common Multiple_](src/algorithms/math/least-common-multiple) (LCM)\n  - `P` [_Sieve of Eratosthenes_](src/algorithms/math/sieve-of-eratosthenes) - menemukan semua bilangan prima hingga batas yang ditentukan\n  - `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_)\n  - `P` [Segitiga Pascal](src/algorithms/math/pascal-triangle)\n  - `P` [Bilangan Kompleks](src/algorithms/math/complex-number) - bilangan kompleks dengan operasi dasarnya\n  - `P` [Radian & Derajat](src/algorithms/math/radian) - konversi radian ke derajat dan sebaliknya\n  - `P` [_Fast Powering_](src/algorithms/math/fast-powering)\n  - `P` [Metode Horner](src/algorithms/math/horner-method) - evaluasi polinomial\n  - `L` [Partisi Bilangan Bulat](src/algorithms/math/integer-partition)\n  - `L` [Akar Pangkat Dua](src/algorithms/math/square-root) - metode Newton\n  - `L` [Algoritma π Liu Hui](src/algorithms/math/liu-hui) - perkiraan perhitungan π berdasarkan segibanyak\n  - `L` [Transformasi Diskrit Fourier](src/algorithms/math/fourier-transform) - menguraikan fungsi waktu (sinyal) menjadi frekuensi yang menyusunnya\n- **Himpunan**\n  - `P` [Produk Kartesian](src/algorithms/sets/cartesian-product) - hasil dari beberapa himpunan\n  - `P` [Pengocokan Fisher–Yates](src/algorithms/sets/fisher-yates) - permutasi acak dari sebuah urutan terhingga\n  - `L` [Himpunan Kuasa](src/algorithms/sets/power-set) - semua himpunan bagian dari sebuah himpunan\n  - `L` [Permutasi](src/algorithms/sets/permutations) (dengan dan tanpa pengulangan)\n  - `L` [Kombinasi](src/algorithms/sets/combinations) (dengan dan tanpa pengulangan)\n  - `L` [_Longest Common Subsequence_](src/algorithms/sets/longest-common-subsequence) (LCS)\n  - `L` [_Longest Increasing Subsequence_](src/algorithms/sets/longest-increasing-subsequence)\n  - `L` [_Shortest Common Supersequence_](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  - `L` [Permasalahan Knapsack](src/algorithms/sets/knapsack-problem) - \"0/1\" dan yang tidak \"dibatasi\"\n  - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray) - \"_Brute Force_\" dan \"Pemrograman Dinamis\" versi Kadane\n  - `L` [_Combination Sum_](src/algorithms/sets/combination-sum) - menemukan semua kombinasi yang membentuk jumlah tertentu\n- **String**\n  - `P` [Jarak Hamming](src/algorithms/string/hamming-distance) - jumlah posisi di mana ditemukan simbol-simbol yang berbeda\n  - `L` [Algoritma Jarak Levenshtein](src/algorithms/string/levenshtein-distance) - _edit distance_ minimum antara dua urutan\n  - `L` [Algoritma Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (Algoritma KMP) - pencarian substring (pencocokan pola)\n  - `L` [Algoritma Z](src/algorithms/string/z-algorithm) - pencarian substring (pencocokan pola)\n  - `L` [Algoritma Rabin Karp](src/algorithms/string/rabin-karp) - pencarian substring\n  - `L` [_Longest Common Substring_](src/algorithms/string/longest-common-substring)\n  - `L` [Pencocokan Ekspresi Reguler](src/algorithms/string/regular-expression-matching)\n- **Pencarian**\n  - `P` [Pencarian Linier](src/algorithms/search/linear-search)\n  - `P` [Pencarian Lompat](src/algorithms/search/jump-search) (atau Block Search) - pencarian di larik tersortir\n  - `P` [Pencarian Biner](src/algorithms/search/binary-search) - pencarian di larik tersortir\n  - `P` [Pencarian Interpolasi](src/algorithms/search/interpolation-search) - pencarian di larik tersortir yang terdistribusi seragam\n- **Penyortiran**\n  - `P` [Sortir Gelembung](src/algorithms/sorting/bubble-sort)\n  - `P` [Sortir Seleksi](src/algorithms/sorting/selection-sort)\n  - `P` [Sortir Sisipan](src/algorithms/sorting/insertion-sort)\n  - `P` [Sortir _Heap_](src/algorithms/sorting/heap-sort)\n  - `P` [Sortir Gabungan](src/algorithms/sorting/merge-sort)\n  - `P` [Sortir Cepat](src/algorithms/sorting/quick-sort) - implementasi _in-place_ dan _non-in-place_\n  - `P` [Sortir Shell](src/algorithms/sorting/shell-sort)\n  - `P` [Sortir Perhitungan](src/algorithms/sorting/counting-sort)\n  - `P` [Sortir Akar](src/algorithms/sorting/radix-sort)\n- **Senarai Berantai**\n  - `P` [Lintas Lurus](src/algorithms/linked-list/traversal)\n  - `P` [Lintas Terbalik](src/algorithms/linked-list/reverse-traversal)\n- **Pohon**\n  - `P` [Pencarian Kedalaman Pertama](src/algorithms/tree/depth-first-search) (DFS)\n  - `P` [Pencarian Luas Pertama](src/algorithms/tree/breadth-first-search) (BFS)\n- **Graf**\n  - `P` [Pencarian Kedalaman Pertama](src/algorithms/graph/depth-first-search) (DFS)\n  - `P` [Pencarian Luas Pertama](src/algorithms/graph/breadth-first-search) (BFS)\n  - `P` [Algoritma Kruskal](src/algorithms/graph/kruskal) - mencari rentang pohon minimum untuk graf tidak berarah berbobot\n  - `L` [Algoritma Dijkstra](src/algorithms/graph/dijkstra) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal\n  - `L` [Algoritma Bellman-Ford](src/algorithms/graph/bellman-ford) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal\n  - `L` [Algoritma Floyd-Warshall](src/algorithms/graph/floyd-warshall) - menemukan jalur terpendek antara semua pasangan sudut\n  - `L` [Mendeteksi Siklus](src/algorithms/graph/detect-cycle) - untuk graf berarah dan tidak berarah (berdasarkan versi DFS dan _Disjoint Set_)\n  - `L` [ALgoritma Prim](src/algorithms/graph/prim) - mencari rentang pohon minimum untuk graf tidak berarah berbobot\n  - `L` [Sortir Topologi](src/algorithms/graph/topological-sorting) - metode DFS\n  - `L` [Poin Artikulasi](src/algorithms/graph/articulation-points) - Algoritma Tarjan (berdasarkan DFS)\n  - `L` [Jembatan](src/algorithms/graph/bridges) - Algoritma berdasarkan DFS\n  - `L` [Jalur dan Sirkuit Eulerian](src/algorithms/graph/eulerian-path) - Algoritma Fleury - Mengunjungi setiap tepinya tepat satu kali\n  - `L` [Siklus Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - mengunjungi setiap sudutnya tepat satu kali\n  - `L` [Komponen yang Terkoneksi dengan Kuat](src/algorithms/graph/strongly-connected-components) - Algoritma Kosaraju\n  - `L` [Permasalahan Penjual Keliling](src/algorithms/graph/travelling-salesman) - kemungkinan rute terpendek untuk mengunjungi setiap kota dan kembali lagi ke kota asal\n- **Kriptografi**\n  - `P` [Polinomial Hash](src/algorithms/cryptography/polynomial-hash) - fungsi rolling hash berdasarkan polinomial\n  - `P` [Sandi Caesar](src/algorithms/cryptography/caesar-cipher) - sandi pengganti sederhana\n- **Pembelajaran Mesin**\n  - `P` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 fungsi JS sederhana yang mengilustrasikan bagaimana mesin-mesin dapat benar-benar belajar (perambatan maju/mundur)\n- **Tidak Dikategorikan**\n  - `P` [Menara Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  - `P` [Perputaran Matriks Persegi](src/algorithms/uncategorized/square-matrix-rotation) - algoritma _in-place_\n  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game) - runut-balik, pemrograman dinamis (atas ke bawah + bawah ke atas) and contoh-contoh _greedy_\n  - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths) - runut-balik, pemrograman dinamis and contoh-contoh beradsarkan Segitiga Pascal\n  - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_ (versi pemrograman dinamis and _brute force_)\n  - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga (4 solusi)\n  - `L` [Permainan N-Queen](src/algorithms/uncategorized/n-queens)\n  - `L` [Permainan Knight's Tour](src/algorithms/uncategorized/knight-tour)\n\n### Algoritma Berdasarkan Paradigma\n\nParadigma 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.\n\n- **_Brute Force_** - melihat ke semua kemungkinan dan memilih solusi yang terbaik\n  - `P` [Pencarian Linier](src/algorithms/search/linear-search)\n  - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_\n  - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga\n  - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray)\n  - `L` [Permasalahan Penjual Keliling](src/algorithms/graph/travelling-salesman) - kemungkinan rute terpendek untuk mengunjungi setiap kota dan kembali lagi ke kota asal\n  - `L` [Transformasi Diskrit Fourier](src/algorithms/math/fourier-transform) - menguraikan fungsi waktu (sinyal) menjadi frekuensi yang menyusunnya\n- **_Greedy_** - memilih pilihan terbaik pada saat ini tanpa mempertimbangkan masa yang akan datang\n  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)\n  - `L` [Permasalahan Knapsack yang Tidak Dibatasi](src/algorithms/sets/knapsack-problem)\n  - `L` [Algoritma Dijkstra](src/algorithms/graph/dijkstra) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal\n  - `L` [Algoritma Prim](src/algorithms/graph/prim) - mencari rentang pohon minimum untuk graf tidak berarah berbobot\n  - `L` [Algoritma Kruskal](src/algorithms/graph/kruskal) - mencari rentang pohon minimum untuk graf tidak berarah berbobot\n- **Memecah dan Menaklukkan** - membagi masalah menjadi bagian-bagian yang kecil, lalu memcahkan bagian-bagian tersebut\n  - `P` [Pencarian Biner](src/algorithms/search/binary-search)\n  - `P` [Menara Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  - `P` [Segitiga Pascal](src/algorithms/math/pascal-triangle)\n  - `P` [Algoritma Euclidean](src/algorithms/math/euclidean-algorithm) - menghitung Faktor Persekutuan Terbesar (FPB)\n  - `P` [Sortir Gabungan](src/algorithms/sorting/merge-sort)\n  - `P` [Sortir Cepat](src/algorithms/sorting/quick-sort)\n  - `P` [Pencarian Kedalaman Pertama untuk Pohon](src/algorithms/tree/depth-first-search) (DFS)\n  - `P` [Pencarian Kedalaman Pertama untuk Graf](src/algorithms/graph/depth-first-search) (DFS)\n  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)\n  - `P` [_Fast Powering_](src/algorithms/math/fast-powering)\n  - `L` [Permutasi](src/algorithms/sets/permutations) (dengan dan tanpa pengulangan)\n  - `L` [Kombinasi](src/algorithms/sets/combinations) (dengan dan tanpa pengulangan)\n- **Pemrograman Dinamis** - membangun sebuah solusi menggunakan upasolusi yang ditemukan sebelumnya\n  - `P` [Bilangan Fibonacci](src/algorithms/math/fibonacci)\n  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)\n  - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths)\n  - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_\n  - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga\n  - `L` [Algoritma Jarak Levenshtein](src/algorithms/string/levenshtein-distance) - _edit distance_ minimum antara dua urutan\n  - `L` [_Longest Common Subsquence_](src/algorithms/sets/longest-common-subsequence) (LCS)\n  - `L` [_Longest Common Substring_](src/algorithms/string/longest-common-substring)\n  - `L` [_Longest Increasing Subsequence_](src/algorithms/sets/longest-increasing-subsequence)\n  - `L` [_Shortest Common Supersequence_](src/algorithms/sets/shortest-common-supersequence)\n  - `L` [Permasalahan Knapsack 0/1](src/algorithms/sets/knapsack-problem)\n  - `L` [Partisi Bilangan Bulat](src/algorithms/math/integer-partition)\n  - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray)\n  - `L` [Algoritma Bellman-Ford](src/algorithms/graph/bellman-ford) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal\n  - `L` [Algoritma Floyd-Warshall](src/algorithms/graph/floyd-warshall) - menemukan jalur terpendek antara semua pasangan sudut\n  - `L` [Pencocokan Ekspresi Reguler](src/algorithms/string/regular-expression-matching)\n- **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.\n  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)\n  - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths)\n  - `P` [Himpunan Kuasa](src/algorithms/sets/power-set) - semua himpunan bagian dari sebuah himpunan\n  - `L` [Siklus Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - mengunjungi setiap sudutnya tepat satu kali\n  - `L` [Permainan N-Queen](src/algorithms/uncategorized/n-queens)\n  - `L` [Permainan Knight's Tour](src/algorithms/uncategorized/knight-tour)\n  - `L` [_Combination Sum_](src/algorithms/sets/combination-sum) - menemukan semua kombinasi yang membentuk jumlah tertentu\n- **_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.\n\n## Cara menggunakan repositori ini\n\n**Meng-_install_ semua dependensi**\n\n```\nnpm install\n```\n\n**Menjalankan ESLint**\n\nAnda dapat menjalankannya untuk memeriksa kualitas kode.\n\n```\nnpm run lint\n```\n\n**Menjalankan semua tes**\n\n```\nnpm test\n```\n\n**Menjalankan tes berdasarkan nama**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**_Playground_**\n\nAnda dapat bermain dengan algoritma dan struktur data di _file_ `./src/playground/playground.js` dan menuliskan tesnya di `./src/playground/__test__/playground.test.js`.\n\nLalu, hanya tinggal menjalankan perintah berikut untuk mengetes apakah kode _playground_ anda bekerja sesuai dengan keinginan:\n\n```\nnpm test -- 'playground'\n```\n\n## Informasi Bermanfaat\n\n### Referensi\n\n[▶ Algoritma dan Struktur Data di YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Notasi _Big O_\n\nNotasi _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_.\n\n![Big O graphs](./assets/big-o-graph.png)\n\nSumber: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nDi bawah ini adalah daftar dari beberapa notasi _Big O_ yang sering digunakan dan perbandingan kinerjanya terhadap berbagai ukuran _input data_.\n\n| Notasi _Big O_ | Komputasi untuk 10 elemen | Komputasi untuk 100 elemen | Komputasi untuk 1000 elemen |\n| -------------- | ------------------------- | -------------------------- | --------------------------- |\n| **O(1)**       | 1                         | 1                          | 1                           |\n| **O(log N)**   | 3                         | 6                          | 9                           |\n| **O(N)**       | 10                        | 100                        | 1000                        |\n| **O(N log N)** | 30                        | 600                        | 9000                        |\n| **O(N^2)**     | 100                       | 10000                      | 1000000                     |\n| **O(2^N)**     | 1024                      | 1.26e+29                   | 1.07e+301                   |\n| **O(N!)**      | 3628800                   | 9.3e+157                   | 4.02e+2567                  |\n\n### Kompleksitas Operasi Struktur Data\n\n| Struktur Data                                | Akses  | Pencarian | Penyisipan | Penghapusan | Keterangan                                               |\n| -------------------------------------------- | :----: | :-------: | :--------: | :---------: | :------------------------------------------------------- |\n| **Array (Larik)**                            |   1    |     n     |     n      |      n      |                                                          |\n| **Stack (Tumpukan)**                         |   n    |     n     |     1      |      1      |                                                          |\n| **Queue (Antrean)**                          |   n    |     n     |     1      |      1      |                                                          |\n| **Linked List (Senarai Berantai)**           |   n    |     n     |     1      |      n      |                                                          |\n| **Hash Table**                               |   -    |     n     |     n      |      n      | Apabila fungsi hash sempurna, biayanya akan menjadi O(1) |\n| **Binary Search Tree (Pohon Telusur Biner)** |   n    |     n     |     n      |      n      | Apabila pohon seimbang, biayanya akan menjadi O(log(n))  |\n| **B-Tree**                                   | log(n) |  log(n)   |   log(n)   |   log(n)    |                                                          |\n| **Red-Black Tree (Pohon Merah-Hitam)**       | log(n) |  log(n)   |   log(n)   |   log(n)    |                                                          |\n| **AVL Tree**                                 | log(n) |  log(n)   |   log(n)   |   log(n)    |                                                          |\n| **Bloom Filter**                             |   -    |     1     |     1      |      -      | Positif palsu dimungkinkan saat pencarian                |\n\n### Kompleksitas Algoritma Sortir Larik\n\n| Nama                                   |    Terbaik    |          Rata-rata           |          Terburuk           | Memori | Stabil | Keterangan                                                                        |\n| -------------------------------------- | :-----------: | :--------------------------: | :-------------------------: | :----: | :----: | :-------------------------------------------------------------------------------- |\n| **Bubble sort (Sortir Gelembung)**     |       n       |        n<sup>2</sup>         |        n<sup>2</sup>        |   1    |   Ya   |                                                                                   |\n| **Insertion sort (Sortir Sisipan)**    |       n       |        n<sup>2</sup>         |        n<sup>2</sup>        |   1    |   Ya   |                                                                                   |\n| **Selection sort (Sortir Seleksi)**    | n<sup>2</sup> |        n<sup>2</sup>         |        n<sup>2</sup>        |   1    | Tidak  |                                                                                   |\n| **Heap sort (Sortir _Heap_)**          | n&nbsp;log(n) |        n&nbsp;log(n)         |        n&nbsp;log(n)        |   1    | Tidak  |                                                                                   |\n| **Merge Sort (Sortir Gabungan)**       | n&nbsp;log(n) |        n&nbsp;log(n)         |        n&nbsp;log(n)        |   n    |   Ya   |                                                                                   |\n| **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 |\n| **Shell sort (Sortir Shell)**          | n&nbsp;log(n) | tergantung pada jarak urutan | n&nbsp;(log(n))<sup>2</sup> |   1    | Tidak  |                                                                                   |\n| **Counting sort (Sortir Perhitungan)** |     n + r     |            n + r             |            n + r            | n + r  |   Ya   | r - angka terbesar dalam larik                                                    |\n| **Radix sort (Sortir Akar)**           |    n \\* k     |            n \\* k            |           n \\* k            | n + k  |   Ya   | k - panjang dari kunci terpanjang                                                 |\n\n## Pendukung Proyek\n\n> Anda dapat mendukung proyek ini via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) atau ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n[Orang-orang yang mendukung proyek ini](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.it-IT.md",
    "content": "# Algoritmi e Strutture Dati in Javascript\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nQuesta repository contiene esempi in Javascript dei più popolari algoritmi e strutture dati .\n\nOgni algortimo e struttura dati ha il suo README separato e la relative spiegazioni e i link per ulteriori approfondimenti (compresi quelli su YouTube).\n\n_Leggilo in altre lingue:_\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Strutture Dati\n\nUna 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.\n\n`P` - Principiante, `A` - Avanzato\n\n* `P` [Lista Concatenata](src/data-structures/linked-list)\n* `P` [Doppia Lista Concatenata](src/data-structures/doubly-linked-list)\n* `P` [Coda](src/data-structures/queue)\n* `P` [Pila](src/data-structures/stack)\n* `P` [Hash Table](src/data-structures/hash-table)\n* `P` [Heap](src/data-structures/heap) - versione massimo e minimo heap\n* `P` [Coda di priorità](src/data-structures/priority-queue)\n* `A` [Trie](src/data-structures/trie)\n* `A` [Albero](src/data-structures/tree)\n  * `A` [Albero binario di ricerca](src/data-structures/tree/binary-search-tree)\n  * `A` [Albero AVL](src/data-structures/tree/avl-tree)\n  * `A` [RB Albero](src/data-structures/tree/red-black-tree)\n  * `A` [Albero Segmentato](src/data-structures/tree/segment-tree) - con  min/max/sum esempi di query\n  * `A` [Albero di Fenwick](src/data-structures/tree/fenwick-tree) (Albero binario indicizzato)\n* `A` [Grafo](src/data-structures/graph) (direzionale e unidirezionale)\n* `A` [Set Disgiunto](src/data-structures/disjoint-set)\n* `A` [Filtro Bloom](src/data-structures/bloom-filter)\n\n## Algoritmi\n\nUn algoritmo è una specifica univoca per risolvere una classe di problemi. È\nun insieme di regole che definiscono con precisione una sequenza di operazioni.\n\n`P` - Principiante, `A` - Avanzato\n\n### Algoritmi per Topic\n\n* **Matematica**\n  * `P` [Manipolazione dei Bit](src/algorithms/math/bits) - set/get/update/clear bits, moltiplicazione/divisione per due, gestire numeri negativi etc.\n  * `P` [Fattoriale](src/algorithms/math/factorial)\n  * `P` [Numeri di Fibonacci](src/algorithms/math/fibonacci) - classico e forma chiusa\n  * `P` [Test di Primalità](src/algorithms/math/primality-test) (metodo del divisore)\n  * `P` [Algoritmo di Euclide](src/algorithms/math/euclidean-algorithm) - trova il massimo comune divisore (MCD)\n  * `P` [Minimo Comune Multiplo](src/algorithms/math/least-common-multiple) (MCM)\n  * `P` [Crivello di Eratostene](src/algorithms/math/sieve-of-eratosthenes) - trova i numeri i primi fino al limite indicato\n  * `P` [Potenza di due](src/algorithms/math/is-power-of-two) - controlla se il numero è una potenza di due\n  * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle)\n  * `P` [Numeri Complessi](src/algorithms/math/complex-number) - numeri complessi e operazioni\n  * `P` [Radiante & Gradi](src/algorithms/math/radian) - conversione da radiante a gradi e viceversa\n  * `P` [Potenza di un Numero](src/algorithms/math/fast-powering)\n  * `A` [Partizione di un Intero](src/algorithms/math/integer-partition)\n  * `A` [Radice Quadrata](src/algorithms/math/square-root) - Metodo di Newton\n  * `A` [Algoritmo di Liu Hui π](src/algorithms/math/liu-hui) - calcolare π usando un poligono\n  * `A` [Trasformata Discreta di Fourier ](src/algorithms/math/fourier-transform) -decomporre una funzione di tempo (un segnale) nelle frequenze che lo compongono\n* **Set**\n  * `P` [Prodotto Cartesiano](src/algorithms/sets/cartesian-product) - moltiplicazione multipla di set\n  * `P` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - permutazione casuale di un sequenza finita\n  * `A` [Power Set](src/algorithms/sets/power-set) - tutti i sottoinsiemi di un set (soluzioni bitwise e backtracking)\n  * `A` [Permutazioni](src/algorithms/sets/permutations) (con e senza ripetizioni)\n  * `A` [Combinazioni](src/algorithms/sets/combinations) (con e senza ripetizioni)\n  * `A` [Massima Sottosequenza Comune](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Massima Sottosequenza Crescente](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Minima Sottosequenza Diffusa](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Problema dello Zaino di Knapsack](src/algorithms/sets/knapsack-problem) - \"0/1\" e \"Senza Restrizioni\"\n  * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray) - \"Brute Force\" e \"Programmazione Dinamica\" versione Kadane\n  * `A` [Somma di Combinazioni](src/algorithms/sets/combination-sum) - ricerca di tutte le combinazioni di una somma\n* **String**\n  * `P` [Distanza di Hamming](src/algorithms/string/hamming-distance) - numero di posizioni in cui i caratteri sono diversi\n  * `A` [Distanza di Levenshtein](src/algorithms/string/levenshtein-distance) - numero minimo di modifiche per rendere uguali due stringhe\n  * `A` [Algoritmo di Knuth-Morris-Pratt](src/algorithms/string/knuth-morris-pratt) (KMP) - ricerca nella sottostringa (pattern matching)\n  * `A` [Algoritmo Z](src/algorithms/string/z-algorithm) - ricerca nella sottostringa (pattern matching)\n  * `A` [Algoritmo di Rabin Karp ](src/algorithms/string/rabin-karp) - ricerca nella sottostringa\n  * `A` [Sottostringa Comune più lunga](src/algorithms/string/longest-common-substring)\n  * `A` [Espressioni Regolari](src/algorithms/string/regular-expression-matching)\n* **Searches**\n  * `P` [Ricerca Sequenziale](src/algorithms/search/linear-search)\n  * `P` [Ricerca a Salti](src/algorithms/search/jump-search) (o Ricerca a Blocchi) - per la ricerca in array ordinati\n  * `P` [Ricerca Binari](src/algorithms/search/binary-search) - per la ricerca in array ordinati\n  * `P` [Ricerca Interpolata](src/algorithms/search/interpolation-search) - per la ricerca in un array ordinato uniformemente distibuito\n* **Sorting**\n  * `P` [Bubble Sort](src/algorithms/sorting/bubble-sort)\n  * `P` [Selection Sort](src/algorithms/sorting/selection-sort)\n  * `P` [Insertion Sort](src/algorithms/sorting/insertion-sort)\n  * `P` [Heap Sort](src/algorithms/sorting/heap-sort)\n  * `P` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `P` [Quicksort](src/algorithms/sorting/quick-sort) - con e senza allocazione di ulteriore memoria\n  * `P` [Shellsort](src/algorithms/sorting/shell-sort)\n  * `P` [Counting Sort](src/algorithms/sorting/counting-sort)\n  * `P` [Radix Sort](src/algorithms/sorting/radix-sort)\n* **Lista Concatenatas**\n  * `P` [Attraversamento Lista Concatenata](src/algorithms/linked-list/traversal)\n  * `P` [Attraversamento Lista Concatenata nel senso Contrario](src/algorithms/linked-list/reverse-traversal)\n* **Alberi**\n  * `P` [Ricerca in Profondità su Alberi](src/algorithms/tree/depth-first-search) (DFS)\n  * `P` [Ricerca in Ampiezza su Alberi](src/algorithms/tree/breadth-first-search) (BFS)\n* **Grafi**\n  * `P` [Ricerca in Profondità su Grafi](src/algorithms/graph/depth-first-search) (DFS)\n  * `P` [Breadth-First Search su Grafi](src/algorithms/graph/breadth-first-search) (BFS)\n  * `P` [Algoritmo di Kruskal](src/algorithms/graph/kruskal) - ricerca dell'Albero con Minima Distanza (MST) per grafi pesati unidirezionali\n  * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice\n  * `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\n  * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) -  ricerca dei percorsi più brevi tra tutte le coppie di vertici\n  * `A` [Rivelamento dei Cicli](src/algorithms/graph/detect-cycle) - per grafici diretti e non diretti (basate su partizioni DFS e Disjoint Set)\n  * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca dell'Albero Ricoprente Minimo (MST) per grafi unidirezionali pesati\n  * `A` [Ordinamento Topologico](src/algorithms/graph/topological-sorting) - metodo DFS\n  * `A` [Punti di Articolazione](src/algorithms/graph/articulation-points) - Algoritmo di Tarjan (basato su DFS)\n  * `A` [Bridges](src/algorithms/graph/bridges) - basato su DFS\n  * `A` [Cammino Euleriano e Circuito Euleriano](src/algorithms/graph/eulerian-path) - Algoritmo di Fleury - Visita ogni margine esattamente una volta\n  * `A` [Ciclo di Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - Visita ad ogni vertice solo una volta\n  * `A` [Componenti Fortemente Connessa](src/algorithms/graph/strongly-connected-components) - algoritmo di Kosaraju\n  * `A` [Problema del Commesso Viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale\n* **Crittografia**\n  * `P` [Hash Polinomiale](src/algorithms/cryptography/polynomial-hash) - Una funzione hash di rolling basata sul polinomio\n* **Senza categoria**\n  * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `P` [Rotazione Matrice Quadrata](src/algorithms/uncategorized/square-matrix-rotation) - algoritmo in memoria\n  * `P` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, programmazione dinamica (top-down + bottom-up) ed esempre di greeedy\n  * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths) - backtracking, programmazione dinamica and l'esempio del Triangolo di Pascal\n  * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola(versione con programmazione dinamica e brute force)\n  * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta(4 soluzioni)\n  * `A` [Rompicapo delle Otto Regine](src/algorithms/uncategorized/n-queens)\n  * `A` [Percorso del Cavallo](src/algorithms/uncategorized/knight-tour)\n\n### Modelli di Algoritmi\n\n Un modello di algoritmo è un generico metodo o approcio che sta alla base della progettazione di una classe di algoritmi.\n Si tratta di un'astrazione ancora più alta di un algoritmo, proprio come un algoritmo è un'astrazione di un programma del computer.\n\n* **Brute Force** - controlla tutte le possibilità e seleziona la migliore\n  * `P` [Ricerca Lineare](src/algorithms/search/linear-search)\n  * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola\n  * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta\n  * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray)\n  * `A` [Problema del commesso viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale\n  * `A` [Trasformata Discreta di Fourier](src/algorithms/math/fourier-transform) - scomporre la funzione (segnale) del tempo in frequenze che la compongono\n* **Greedy** - scegliere l'opzione migliore al momento d'eleborazione dell'algoritmo, senza alcuna considerazione per il futuro\n  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `A` [Problema dello Zaino di Knapsack](src/algorithms/sets/knapsack-problem)\n  * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca del percorso più breve tra tutti i vertici del grafo\n  * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca del Minimo Albero Ricoprente per grafi pesati e unidirezionali\n  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n* **Divide e Conquista** - divide il problema in piccole parti e risolve ogni parte\n  * `P` [Ricerca Binaria](src/algorithms/search/binary-search)\n  * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle)\n  * `P` [Algoritmo di Euclide](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)\n  * `P` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `P` [Quicksort](src/algorithms/sorting/quick-sort)\n  * `P` [Albero per Ricerca in Profondità](src/algorithms/tree/depth-first-search) (DFS)\n  * `P` [Grafo per Ricerca in Profondità](src/algorithms/graph/depth-first-search) (DFS)\n  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `P` [Algoritmo di Elevamento a Potenza](src/algorithms/math/fast-powering)\n  * `A` [Permutazioni](src/algorithms/sets/permutations) (con o senza ripetizioni)\n  * `A` [Combinazioni](src/algorithms/sets/combinations) (con o senza ripetizioni)\n* **Programmazione Dinamica** - creare una soluzione utilizzando le sub-solution trovate in precedenza\n  * `P` [Numero di Fibonacci](src/algorithms/math/fibonacci)\n  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths)\n  * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola\n  * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta\n  * `A` [Distanza di Levenshtein](src/algorithms/string/levenshtein-distance) - minima variazione tra due sequenze\n  * `A` [La Più Lunga Frequente SottoSequenza](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [La Più Lunga Frequente SubString](src/algorithms/string/longest-common-substring)\n  * `A` [La Più Lunga SottoSequenza Crescente](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [La Più Corta e Frequente SuperSequenza](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Problema dello zaino](src/algorithms/sets/knapsack-problem)\n  * `A` [Partizione di un Intero](src/algorithms/math/integer-partition)\n  * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray)\n  * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca del percorso più breve per tutti i vertici del grafo\n  * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) - ricerca del percorso più breve tra tutte le coppie di vertici\n  * `A` [Espressioni Regolari](src/algorithms/string/regular-expression-matching)\n* **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.\n  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths)\n  * `P` [Power Set](src/algorithms/sets/power-set) - tutti i subset di un set\n  * `A` [Ciclo di Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - visita di tutti i vertici solamente una volta\n  * `A` [Problema di N-Queens](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n  * `A` [Combinazioni di una Somma](src/algorithms/sets/combination-sum) - trovare tutte le combinazioni che compongono una somma\n* **Branch & Bound** - ricordatevi che la soluzione meno costosa trovata ad ogni step durante il backtracking e\nil costo di usare la soluzione meno costosa trovata fino al limite inferiore al costo minimo della soluzione al problema,\nal fine di scartare soluzioni parziali con costi maggiori della soluzione meno costosa trovata .\nDi solito si usa BFS trasversale in combinazione con DFS trasversale .\n\n## Come usare questa repository\n\n**Installare tutte le dipendenze**\n```\nnpm install\n```\n\n**Eseguire ESLint**\n\nPotresti usarlo per controllare la qualità del codice.\n\n```\nnpm run lint\n```\n\n**Eseguire tutti i test**\n```\nnpm test\n```\n\n**Eseguire un test tramite il nome**\n```\nnpm test -- 'LinkedList'\n```\n\n**Playground**\n\nSe vuoi puoi giocare le strutture dati e gli algoritmi nel file ./src/playground/playground.js` e\nscrivere test nel file `./src/playground/__test__/playground.test.js`.\n\nPoi puoi semplicemente eseguire il seguente comando per testare quello che hai scritto :\n\n```\nnpm test -- 'playground'\n```\n\n## Informazioni Utili\n\n### Bibliografia\n\n[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Notazione Big O\n\n* La notazione Big O* è usata per classificare algoritmi in base al tempo di esecuzione o ai\nrequisiti di spazio che crescono in base alla crescita dell'input .\nNella grafico qua sotto puoi trovare gli ordini di crescita più comuni degli algoritmi usando la notazione Big O.\n\n![Grafi Big O ](./assets/big-o-graph.png)\n\nRiferimento: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nNella tabella qua sotto ci sono riportate la lista delle notazioni Big O più usate e delle loro prestazioni comparate tra differenti grandezze d'input .\n\n| Notazione Big O | Computazione con 10 elementi | Computazione con 100 elementi | Computazione con 1000 elementi  |\n| --------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**        | 1                            | 1                             | 1                               |\n| **O(log N)**    | 3                            | 6                             | 9                               |\n| **O(N)**        | 10                           | 100                           | 1000                            |\n| **O(N log N)**  | 30                           | 600                           | 9000                            |\n| **O(N^2)**      | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**      | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**       | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### Complessità delle Operazion sulle Strutture Dati\n\n| Struttura Dati          | Accesso   | Ricerca   | Inserimento | Rimozione | Commenti  |\n| ----------------------- | :-------: | :-------: | :--------:  | :-------: | :-------- |\n| **Array**               | 1         | n         | n           | n         |           |\n| **Pila**                | n         | n         | 1           | 1         |           |\n| **Coda**                | n         | n         | 1           | 1         |           |\n| **Lista Concatenata**   | n         | n         | 1           | n         |           |\n| **Tabella Hash**        | -         | n         | n           | n         | Nel caso di una funzione di hashing perfetta il costo sarebbe O(1)|\n| **Binary Search Tree**  | n         | n         | n           | n         | Nel caso di albero bilanciato il costo sarebbe O(log(n)) |\n| **B-Tree**              | log(n)    | log(n)    | log(n)      | log(n)    |           |\n| **Red-Black Tree**      | log(n)    | log(n)    | log(n)      | log(n)    |           |\n| **Albero AVL**          | log(n)    | log(n)    | log(n)      | log(n)    |           |\n| **Bloom Filter**        | -         | 1         | 1           | -         | Falsi positivi sono possibili durante la ricerca |\n\n### Complessità degli Algoritmi di Ordinamento di Array\n\n| Nome                  | Milgiore        | Media               | Perggiore           | Memoria   | Stabile   | Commenti  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |\n| **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)) |\n| **Shell sort**        | n&nbsp;log(n)   | dipende dagli spazi vuoti nella sequenza  | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - numero più grande nell'array |\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - lunghezza della chiave più grande |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.ja-JP.md",
    "content": "# JavaScriptアルゴリズムとデータ構造\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nこのリポジトリには、JavaScriptベースの一般的なアルゴリズムとデータ構造に関する多数のサンプルが含まれています。\n\n\n各アルゴリズムとデータ構造には独自のREADMEがあります。\n関連する説明、そして参考資料 (YouTube動画)も含まれています。\n\n_Read this in other languages:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## データ構造\n\nデータ構造は、データ値、データ値との間の関係、\nそして、データを扱うことができる関数と演算の集合で、\nデータを特定の方法で構成して保存することで、より効率的に\nアクセスして変更することができます。\n\n`B` - 初心者, `A` - 上級\n\n* `B` [リンクされたリスト](src/data-structures/linked-list)\n* `B` [二重リンクリスト](src/data-structures/doubly-linked-list)\n* `B` [キュー](src/data-structures/queue)\n* `B` [スタック](src/data-structures/stack)\n* `B` [ハッシュ表](src/data-structures/hash-table)\n* `B` [ヒープ](src/data-structures/heap) - max and min heap versions\n* `B` [優先度キュー](src/data-structures/priority-queue)\n* `A` [トライ](src/data-structures/trie)\n* `A` [ツリー](src/data-structures/tree)\n  * `A` [バイナリ検索ツリー](src/data-structures/tree/binary-search-tree)\n  * `A` [AVLツリー](src/data-structures/tree/avl-tree)\n  * `A` [赤黒のツリー](src/data-structures/tree/red-black-tree)\n  * `A` [セグメントツリー](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples\n  * `A` [フェンウィック・ツリー](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)\n* `A` [グラフ](src/data-structures/graph) (both directed and undirected)\n* `A` [分離集合](src/data-structures/disjoint-set)\n* `A` [ブルームフィルタ](src/data-structures/bloom-filter)\n\n## アルゴリズム\n\nアルゴリズムとは、問題のクラスをどのように解決するかの明確な仕様です。\n一連の操作を正確に定義する一連のルールです。\n\n`B` - 初心者, `A` - 上級\n\n### トピック別アルゴリズム\n\n* **数学**\n  * `B` [ビット操作](src/algorithms/math/bits) - set/get/update/clear bits, 2つの乗算/除算, 否定的にする. 等\n  * `B` [因果関係](src/algorithms/math/factorial)\n  * `B` [フィボナッチ数](src/algorithms/math/fibonacci) - クラシックとクローズドフォームのバージョン\n  * `B` [素数性テスト](src/algorithms/math/primality-test) (trial division 方法)\n  * `B` [ユークリッドアルゴリズム](src/algorithms/math/euclidean-algorithm) - 最大公約数を計算する (GCD)\n  * `B` [最小公倍数](src/algorithms/math/least-common-multiple) (LCM)\n  * `B` [エラトステネスのふるい](src/algorithms/math/sieve-of-eratosthenes) - 与えられた限度まですべての素数を見つける\n  * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - 数値が2の累乗であるかどうかを調べる（単純なアルゴリズムとビットごとのアルゴリズム）\n  * `B` [パスカルの三角形](src/algorithms/math/pascal-triangle)\n  * `B` [複素数](src/algorithms/math/complex-number) - 複素数とその基本演算\n  * `B` [ラジアン＆度](src/algorithms/math/radian) - 度数と逆方向の変換に対するラジアン\n  * `B` [高速電力供給](src/algorithms/math/fast-powering)\n  * `A` [整数パーティション](src/algorithms/math/integer-partition)\n  * `A` [Liu Hui π アルゴリズム](src/algorithms/math/liu-hui) - N-gonsに基づく近似π計算\n  * `A` [離散フーリエ変換](src/algorithms/math/fourier-transform) - 時間（信号）の関数をそれを構成する周波数に分解する\n* **セット**\n  * `B` [デカルト積 ](src/algorithms/sets/cartesian-product) - 複数の積の積\n  * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - 有限シーケンスのランダム置換\n  * `A` [パワーセット](src/algorithms/sets/power-set) - セットのすべてのサブセット（ビットごとのソリューションとバックトラッキングソリューション）\n  * `A` [順列](src/algorithms/sets/permutations) （繰り返しの有無にかかわらず）\n  * `A` [組み合わせ](src/algorithms/sets/combinations) （繰返しあり、繰返しなし）\n  * `A` [最長共通部分列](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [最長増加サブシーケンス](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [最短共通スーパーシーケンス](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [ナップザック問題 ](src/algorithms/sets/knapsack-problem) - 「0/1」と「非結合」問題\n  * `A` [最大サブアレイ](src/algorithms/sets/maximum-subarray) - 「ブルートフォース」と「ダイナミックプログラミング」（Kadane's版）\n  * `A` [組み合わせ合計](src/algorithms/sets/combination-sum) - 特定の合計を構成するすべての組み合わせを見つける\n* **文字列**\n  * `B` [ハミング距離](src/algorithms/string/hamming-distance) - シンボルが異なる位置の数\n  * `A` [レーベンシュタイン距離](src/algorithms/string/levenshtein-distance) - 2つのシーケンス間の最小編集距離\n  * `A` [Knuth-Morris-Prattアルゴリズム](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - 部分文字列検索 (pattern matching)\n  * `A` [Z アルゴリズム](src/algorithms/string/z-algorithm) - 部分文字列検索 (pattern matching)\n  * `A` [Rabin Karpアルゴリズム](src/algorithms/string/rabin-karp) - 部分文字列検索\n  * `A` [最長共通部分文字列](src/algorithms/string/longest-common-substring)\n  * `A` [正規表現マッチング](src/algorithms/string/regular-expression-matching)\n* **検索**\n  * `B` [リニアサーチ](src/algorithms/search/linear-search)\n  * `B` [ジャンプ検索](src/algorithms/search/jump-search) (Jump Search) - ソートされた配列で検索\n  * `B` [バイナリ検索](src/algorithms/search/binary-search) - ソートされた配列で検索\n  * `B` [補間探索](src/algorithms/search/interpolation-search) - 一様分布のソート配列で検索する\n* **並べ替え**\n  * `B` [バブルソート](src/algorithms/sorting/bubble-sort)\n  * `B` [選択ソート](src/algorithms/sorting/selection-sort)\n  * `B` [挿入ソート](src/algorithms/sorting/insertion-sort)\n  * `B` [ヒープソート](src/algorithms/sorting/heap-sort)\n  * `B` [マージソート](src/algorithms/sorting/merge-sort)\n  * `B` [クイックソート](src/algorithms/sorting/quick-sort) -インプレースおよび非インプレース・インプリメンテーション\n  * `B` [シェルソート](src/algorithms/sorting/shell-sort)\n  * `B` [並べ替えを数える](src/algorithms/sorting/counting-sort)\n  * `B` [基数ソート](src/algorithms/sorting/radix-sort)\n* **リンクされたリスト**\n  * `B` [ストレートトラバーサル](src/algorithms/linked-list/traversal)\n  * `B` [逆方向のトラバーサル](src/algorithms/linked-list/reverse-traversal)\n* **ツリー**\n  * `B` [深度優先検索](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [幅優先検索](src/algorithms/tree/breadth-first-search) (BFS)\n* **グラフ**\n  * `B` [深度優先検索](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [幅優先検索](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Kruskalのアルゴリズム](src/algorithms/graph/kruskal) - 重み付き無向グラフの最小スパニングツリー（MST）の発見\n  * `A` [Dijkstraアルゴリズム](src/algorithms/graph/dijkstra) - 単一の頂点からすべてのグラフ頂点への最短経路を見つける\n  * `A` [Bellman-Fordアルゴリズム](src/algorithms/graph/bellman-ford) - 単一の頂点からすべてのグラフ頂点への最短経路を見つける\n  * `A` [Floyd-Warshallアルゴリズム](src/algorithms/graph/floyd-warshall) - すべての頂点ペア間の最短経路を見つける\n  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - 有向グラフと無向グラフの両方（DFSおよびディスジョイントセットベースのバージョン）\n  * `A` [プリムのアルゴリズム](src/algorithms/graph/prim) - 重み付き無向グラフの最小スパニングツリー（MST）の発見\n  * `A` [トポロジカルソート](src/algorithms/graph/topological-sorting) - DFSメソッド\n  * `A` [アーティキュレーションポイント](src/algorithms/graph/articulation-points) - Tarjanのアルゴリズム（DFSベース）\n  * `A` [ブリッジ ](src/algorithms/graph/bridges) - DFSベースのアルゴリズム\n  * `A` [オイラーパスとオイラー回路](src/algorithms/graph/eulerian-path) - フルリーアルゴリズム - すべてのエッジを正確に1回訪問する\n  * `A` [ハミルトニアンサイクル](src/algorithms/graph/hamiltonian-cycle) - すべての頂点を正確に1回訪問する\n  * `A` [強連結成分](src/algorithms/graph/strongly-connected-components) - コサラジュのアルゴリズム\n  * `A` [トラベリングセールスマン問題](src/algorithms/graph/travelling-salesman) - 各都市を訪問し、起点都市に戻る最短経路\n* **暗号**\n  * `B` [多項式ハッシュ](src/algorithms/cryptography/polynomial-hash) - 関数多項式に基づくハッシュ関数\n* **未分類**\n  * `B` [ハノイの塔](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [正方行列回転](src/algorithms/uncategorized/square-matrix-rotation) - インプレイスアルゴリズム\n  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game) - バックトラック、ダイナミックプログラミング（トップダウン+ボトムアップ）、欲張りの例\n  * `B` [ユニークなパス](src/algorithms/uncategorized/unique-paths) - バックトラック、動的プログラミング、PascalのTriangleベースの例\n  * `B` [レインテラス](src/algorithms/uncategorized/rain-terraces) - トラップ雨水問題（ダイナミックプログラミングとブルートフォースバージョン）\n  * `B` [再帰的階段](src/algorithms/uncategorized/recursive-staircase) - 上に到達する方法の数を数える（4つのソリューション）\n  * `A` [N-クイーンズ問題](src/algorithms/uncategorized/n-queens)\n  * `A` [ナイトツアー](src/algorithms/uncategorized/knight-tour)\n\n### Paradigmによるアルゴリズム\n\nアルゴリズムパラダイムは、あるクラスのアルゴリズムの設計の基礎をなす一般的な方法またはアプローチである。それは、アルゴリズムがコンピュータプログラムよりも高い抽象であるのと同様に、アルゴリズムの概念よりも高い抽象である。\n* **ブルートフォース** - すべての可能性を見て最適なソリューションを選択する\n  * `B` [線形探索](src/algorithms/search/linear-search)\n  * `B` [レインテラス](src/algorithms/uncategorized/rain-terraces) - 雨水問題\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - 先頭に到達する方法の数を数えます\n  * `A` [最大サブアレイ](src/algorithms/sets/maximum-subarray)\n  * `A` [旅行セールスマン問題](src/algorithms/graph/travelling-salesman) - 各都市を訪れ、起点都市に戻る最短ルート\n  * `A` [離散フーリエ変換](src/algorithms/math/fourier-transform) - 時間（信号）の関数をそれを構成する周波数に分解する\n* **欲張り** - 未来を考慮することなく、現時点で最適なオプションを選択する\n  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)\n  * `A` [結合されていないナップザック問題](src/algorithms/sets/knapsack-problem)\n  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - すべてのグラフ頂点への最短経路を見つける\n  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - 重み付き無向グラフの最小スパニングツリー（MST）を見つける\n  * `A` [Kruskalのアルゴリズム](src/algorithms/graph/kruskal) - 重み付き無向グラフの最小スパニングツリー（MST）を見つける\n* **分割と征服** - 問題をより小さな部分に分割し、それらの部分を解決する\n  * `B` [バイナリ検索](src/algorithms/search/binary-search)\n  * `B` [ハノイの塔](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [パスカルの三角形](src/algorithms/math/pascal-triangle)\n  * `B` [ユークリッドアルゴリズム](src/algorithms/math/euclidean-algorithm) - GCD（Greatest Common Divisor）を計算する\n  * `B` [マージソート](src/algorithms/sorting/merge-sort)\n  * `B` [クイックソート](src/algorithms/sorting/quick-sort)\n  * `B` [ツリーの深さ優先検索](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [グラフの深さ優先検索](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)\n  * `B` [高速電力供給](src/algorithms/math/fast-powering)\n  * `A` [順列](src/algorithms/sets/permutations) （繰り返しの有無にかかわらず）\n  * `A` [組み合わせ](src/algorithms/sets/combinations)（繰返しあり、繰返しなし）\n* **動的プログラミング** - 以前に発見されたサブソリューションを使用してソリューションを構築する\n  * `B` [フィボナッチ数](src/algorithms/math/fibonacci)\n  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)\n  * `B` [ユニークなパス](src/algorithms/uncategorized/unique-paths)\n  * `B` [雨テラス](src/algorithms/uncategorized/rain-terraces) - トラップ雨水問題\n  * `B` [再帰的階段](src/algorithms/uncategorized/recursive-staircase) - 上に到達する方法の数を数える\n  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - 2つのシーケンス間の最小編集距離\n  * `A` [最長共通部分列](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [最長共通部分文字列](src/algorithms/string/longest-common-substring)\n  * `A` [最長増加サブシーケンス](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [最短共通共通配列](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [0/1ナップザック問題](src/algorithms/sets/knapsack-problem)\n  * `A` [整数パーティション](src/algorithms/math/integer-partition)\n  * `A` [最大サブアレイ](src/algorithms/sets/maximum-subarray)\n  * `A` [Bellman-Fordアルゴリズム](src/algorithms/graph/bellman-ford) - すべてのグラフ頂点への最短経路を見つける\n  * `A` [Floyd-Warshallアルゴリズム](src/algorithms/graph/floyd-warshall) - すべての頂点ペア間の最短経路を見つける\n  * `A` [正規表現マッチング](src/algorithms/string/regular-expression-matching)\n* **バックトラッキング** - ブルートフォースと同様に、可能なすべてのソリューションを生成しようとしますが、\n  次のソリューションを生成するたびにすべての条件を満たすかどうかをテストし、それ以降は引き続きソリューションを生成します。\n  それ以外の場合は、バックトラックして、解決策を見つける別の経路に進みます。\n  通常、状態空間のDFSトラバーサルが使用されています。\n  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)\n  * `B` [ユニークなパス](src/algorithms/uncategorized/unique-paths)\n  * `B` [パワーセット](src/algorithms/sets/power-set) - セットのすべてのサブセット\n  * `A` [ハミルトニアンサイクル](src/algorithms/graph/hamiltonian-cycle) - すべての頂点を正確に1回訪問する\n  * `A` [N-クイーンズ問題](src/algorithms/uncategorized/n-queens)\n  * `A` [ナイトツアー](src/algorithms/uncategorized/knight-tour)\n  * `A` [組み合わせ合計](src/algorithms/sets/combination-sum) - 特定の合計を構成するすべての組み合わせを見つける\n* **ブランチ＆バウンド** - バックトラック検索の各段階で見つかった最もコストの低いソリューションを覚えておいて、最もコストの低いソリューションのコストを使用します。これまでに発見された最もコストの低いソリューションよりも大きなコストで部分ソリューションを破棄するように指示します。通常、状態空間ツリーのDFSトラバーサルと組み合わせたBFSトラバーサルが使用されています。\n\n## このリポジトリの使い方\n\n**すべての依存関係をインストールする**\n```\nnpm install\n```\n\n**ESLintを実行する**\n\nこれを実行してコードの品質をチェックすることができます。\n\n```\nnpm run lint\n```\n\n**すべてのテストを実行する**\n```\nnpm test\n```\n\n**名前でテストを実行する**\n```\nnpm test -- 'LinkedList'\n```\n\n**playground**\n\nデータ構造とアルゴリズムを `./src/playground/playground.js` ファイルで再生し、\nそれに対するテストを書くことができ `./src/playground/__test__/playground.test.js`.\n\n次に、次のコマンドを実行して、遊び場コードが正常に動作するかどうかをテストします。\n\n```\nnpm test -- 'playground'\n```\n\n## 有用な情報\n\n### 参考文献\n\n[▶ データ構造とアルゴリズム on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### ビッグO表記\n\n*Big O表記法は* 入力サイズが大きくなるにつれて実行時間やスペース要件がどのように増加するかに応じてアルゴリズムを分類するために使用されます。下のチャートでは、Big O表記で指定されたアルゴリズムの成長の最も一般的な順序を見つけることができます。\n\n![Big Oグラフ](./assets/big-o-graph.png)\n\n出典: [Big Oチートシート](http://bigocheatsheet.com/).\n\n以下は、最も使用されているBig O表記のリストと、入力データのさまざまなサイズに対するパフォーマンス比較です。\n\n| Big O Notation | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements  |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### データ構造操作の複雑さ\n\n| Data Structure          | Access    | Search    | Insertion | Deletion  | Comments  |\n| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |\n| **Array**               | 1         | n         | n         | n         |           |\n| **Stack**               | n         | n         | 1         | 1         |           |\n| **Queue**               | n         | n         | 1         | 1         |           |\n| **Linked List**         | n         | n         | 1         | 1         |           |\n| **Hash Table**          | -         | n         | n         | n         | In case of perfect hash function costs would be O(1) |\n| **Binary Search Tree**  | n         | n         | n         | n         | In case of balanced tree costs would be O(log(n)) |\n| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Bloom Filter**        | -         | 1         | 1         | -         | False positives are possible while searching |\n\n### 配列の並べ替えアルゴリズムの複雑さ\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |\n| **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 |\n| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - biggest number in array |\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - length of longest key |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.ko-KR.md",
    "content": "# JavaScript 알고리즘 및 자료 구조\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\n이 저장소에는 많이 알려진 알고리즘 및 자료 구조의 Javascript 기반 예제를 담고 있습니다.\n\n각 알고리즘과 자료 구조에 대해 연관되어 있는 설명이 README에 작성되어 있으며,\n링크를 통해 더 자세한 설명을 만날 수 있습니다. (관련된 YouTube 영상도 포함).\n\n_Read this in other languages:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## 자료 구조\n\n자료 구조는 데이터를 특정 방식으로 구성하고 저장함으로써 더 효율적으로\n접근하고 수정할 수 있게 해줍니다. 간단히 말해, 자료 구조는 데이터 값들,\n데이터 간의 관계, 그리고 데이터를 다룰 수 있는 함수와 작업의 모임입니다.\n\n\n`B` - 입문자, `A` - 숙련자\n\n* `B` [연결 리스트](src/data-structures/linked-list)\n* `B` [이중 연결 리스트](src/data-structures/doubly-linked-list)\n* `B` [큐](src/data-structures/queue)\n* `B` [스택](src/data-structures/stack)\n* `B` [해시 테이블](src/data-structures/hash-table)\n* `B` [힙](src/data-structures/heap)\n* `B` [우선순위 큐](src/data-structures/priority-queue)\n* `A` [트라이](src/data-structures/trie)\n* `A` [트리](src/data-structures/tree)\n  * `A` [이진 탐색 트리](src/data-structures/tree/binary-search-tree)\n  * `A` [AVL 트리](src/data-structures/tree/avl-tree)\n  * `A` [Red-Black 트리](src/data-structures/tree/red-black-tree)\n  * `A` [세그먼트 트리](src/data-structures/tree/segment-tree) - min/max/sum range 쿼리 예제.\n  * `A` [Fenwick 트리](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)\n* `A` [그래프](src/data-structures/graph) (유방향, 무방향)\n* `A` [서로소 집합](src/data-structures/disjoint-set)\n* `A` [블룸 필터](src/data-structures/bloom-filter)\n\n## 알고리즘\n\n알고리즘은 어떤 종류의 문제를 풀 수 있는 정확한 방법이며,\n일련의 작업을 정확하게 정의해 놓은 규칙들입니다.\n\n`B` - 입문자, `A` - 숙련자\n\n### 주제별 알고리즘\n\n* **Math**\n  * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, 2의 곱 / 나누기, 음수로 만들기 etc.\n  * `B` [팩토리얼](src/algorithms/math/factorial)\n  * `B` [피보나치 수](src/algorithms/math/fibonacci)\n  * `B` [소수 판별](src/algorithms/math/primality-test) (trial division 방식)\n  * `B` [유클리드 호제법](src/algorithms/math/euclidean-algorithm) - 최대공약수 (GCD)\n  * `B` [최소 공배수](src/algorithms/math/least-common-multiple) - LCM\n  * `B` [에라토스테네스의 체](src/algorithms/math/sieve-of-eratosthenes) - 특정수 이하의 모든 소수 찾기\n  * `B` [2의 거듭제곱 판별법](src/algorithms/math/is-power-of-two) - 어떤 수가 2의 거듭제곱인지 판별 (naive 와 bitwise 알고리즘)\n  * `B` [파스칼 삼각형](src/algorithms/math/pascal-triangle)\n  * `A` [자연수 분할](src/algorithms/math/integer-partition)\n  * `A` [리우 후이 π 알고리즘](src/algorithms/math/liu-hui) - N-각형을 기반으로 π 근사치 구하기\n* **Sets**\n  * `B` [카티지언 프로덕트](src/algorithms/sets/cartesian-product) - 곱집합\n  * `B` [Fisher–Yates 셔플](src/algorithms/sets/fisher-yates) - 유한 시퀀스의 무작위 순열\n  * `A` [멱집합](src/algorithms/sets/power-set) - 집합의 모든 부분집합\n  * `A` [순열](src/algorithms/sets/permutations) (반복 유,무)\n  * `A` [조합](src/algorithms/sets/combinations) (반복 유,무)\n  * `A` [최장 공통 부분수열](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [최장 증가 수열](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [배낭 문제](src/algorithms/sets/knapsack-problem) - \"0/1\" 과 \"Unbound\"\n  * `A` [최대 구간합](src/algorithms/sets/maximum-subarray) - \"브루트 포스\" 과 \"동적 계획법\" (Kadane's) 버전\n  * `A` [조합 합](src/algorithms/sets/combination-sum) - 특정 합을 구성하는 모든 조합 찾기\n* **Strings**\n  * `B` [해밍 거리](src/algorithms/string/hamming-distance) - 심볼이 다른 위치의 갯수\n  * `A` [편집 거리](src/algorithms/string/levenshtein-distance) - 두 시퀀스 간위 최소 편집거리\n  * `A` [커누스-모리스-프랫 알고리즘](src/algorithms/string/knuth-morris-pratt) (KMP 알고리즘) - 부분 문자열 탐색 (패턴 매칭)\n  * `A` [Z 알고리즘](src/algorithms/string/z-algorithm) - 부분 문자열 탐색 (패턴 매칭)\n  * `A` [라빈 카프 알고리즘](src/algorithms/string/rabin-karp) - 부분 문자열 탐색\n  * `A` [최장 공통 부분 문자열](src/algorithms/string/longest-common-substring)\n  * `A` [정규 표현식 매칭](src/algorithms/string/regular-expression-matching)\n* **Searches**\n  * `B` [선형 탐색](src/algorithms/search/linear-search)\n  * `B` [점프 탐색](src/algorithms/search/jump-search) (or Block Search) - 정렬된 배열에서 탐색\n  * `B` [이진 탐색](src/algorithms/search/binary-search) - 정렬된 배열에서 탐색\n  * `B` [보간 탐색](src/algorithms/search/interpolation-search) - 균등한 분포를 이루는 정렬된 배열에서 탐색\n* **Sorting**\n  * `B` [거품 정렬](src/algorithms/sorting/bubble-sort)\n  * `B` [선택 정렬](src/algorithms/sorting/selection-sort)\n  * `B` [삽입 정렬](src/algorithms/sorting/insertion-sort)\n  * `B` [힙 정렬](src/algorithms/sorting/heap-sort)\n  * `B` [병합 정렬](src/algorithms/sorting/merge-sort)\n  * `B` [퀵 정렬](src/algorithms/sorting/quick-sort) - 제자리(in-place)와 제자리가 아닌(non-in-place) 구현\n  * `B` [셸 정렬](src/algorithms/sorting/shell-sort)\n  * `B` [계수 정렬](src/algorithms/sorting/counting-sort)\n  * `B` [기수 정렬](src/algorithms/sorting/radix-sort)\n* **Trees**\n  * `B` [깊이 우선 탐색](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [너비 우선 탐색](src/algorithms/tree/breadth-first-search) (BFS)\n* **Graphs**\n  * `B` [깊이 우선 탐색](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [너비 우선 탐색](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [크루스칼 알고리즘](src/algorithms/graph/kruskal) - 최소 신장 트리 찾기 (MST) 무방향 가중 그래프\n  * `A` [다익스트라 알고리즘](src/algorithms/graph/dijkstra) - 한 점에서 다른 모든 점까지 최단 거리 찾기\n  * `A` [벨만-포드 알고리즘](src/algorithms/graph/bellman-ford) - 한 점에서 다른 모든 점까지 최단 거리 찾기\n  * `A` [플로이드-워셜 알고리즘](src/algorithms/graph/floyd-warshall) - 모든 종단 간의 최단거리 찾기\n  * `A` [사이클 탐지](src/algorithms/graph/detect-cycle) - 유방향, 무방향 그래프 (DFS 와 Disjoint Set 에 기반한 버전)\n  * `A` [프림 알고리즘](src/algorithms/graph/prim) - 무방향 가중치 그래프에서 최소 신장 트리 (MST) 찾기\n  * `A` [위상 정렬](src/algorithms/graph/topological-sorting) - DFS 방식\n  * `A` [단절점](src/algorithms/graph/articulation-points) - 타잔의 알고리즘 (DFS 기반)\n  * `A` [단절선](src/algorithms/graph/bridges) - DFS 기반 알고리즘\n  * `A` [오일러 경로 와 오일러 회로](src/algorithms/graph/eulerian-path) - Fleury의 알고리즘 - 모든 엣지를 한번만 방문\n  * `A` [해밀턴 경로](src/algorithms/graph/hamiltonian-cycle) - 모든 꼭짓점을 한번만 방문\n  * `A` [강결합 컴포넌트](src/algorithms/graph/strongly-connected-components) - Kosaraju의 알고리즘\n  * `A` [외판원 문제](src/algorithms/graph/travelling-salesman) - 각 도시를 다 방문하고 다시 출발점으로 돌아오는 최단 경로 찾기\n* **Uncategorized**\n  * `B` [하노이 탑](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [정방 행렬 회전](src/algorithms/uncategorized/square-matrix-rotation) - 제자리(in-place) 알고리즘\n  * `B` [점프 게임](src/algorithms/uncategorized/jump-game) - 백트래킹, 동적계획법 (top-down + bottom-up), 탐욕 알고리즘 예제\n  * `B` [Unique 경로](src/algorithms/uncategorized/unique-paths) - 백트래킹, 동적계획법, 파스칼 삼각형에 기반한 예제\n  * `B` [빗물 담기 문제](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (동적계획법, 브루트포스 버전)\n  * `A` [N-Queens 문제](src/algorithms/uncategorized/n-queens)\n  * `A` [기사의 여행 문제](src/algorithms/uncategorized/knight-tour)\n\n### 패러다임별 알고리즘\n\n알고리즘 패러다임 이란, 알고리즘이 주어진 문제를 해결하기 위해 채택한 기초가 되는 일반적인 방법 혹은 접근법입니다. 알고리즘이 해결하는 문제나 알고리즘의 동작 방식이 완전히 다르더라도,알고리즘의 동작 원칙이 같으면 같은 패러다음을 사용했다고 말할 수 있으며, 주로 알고리즘을 구분하는 기준으로 쓰인다. 알고리즘이 일반적인 컴퓨터의 프로그램에 대한 개념보다 보다 더 추상적인 개념인 것처럼 알고리즘의 패러다임은 명확히 정의된 수학적 실체가 있는 것이 아니기 때문에 그 어떤 알고리즘의 개념보다도 훨씬 추상적인 개념입니다.\n\n* **브루트 포스(Brute Force)** - 가능한 모든 경우를 탐색한 뒤 최적을 찾아내는 방식입니다.\n  * `B` [선형 탐색](src/algorithms/search/linear-search)\n  * `B` [빗물 담기 문제](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem\n  * `A` [최대 구간합](src/algorithms/sets/maximum-subarray)\n  * `A` [외판원 문제](src/algorithms/graph/travelling-salesman) - 각 도시를 다 방문하고 다시 출발점으로 돌아오는 최단 경로 찾기\n* **탐욕 알고리즘(Greedy)** - 이후를 고려하지 않고 현재 시점에서 가장 최적인 선택을 하는 방식입니다.\n  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)\n  * `A` [쪼갤수 있는 배낭 문제](src/algorithms/sets/knapsack-problem)\n  * `A` [다익스트라 알고리즘](src/algorithms/graph/dijkstra) - 모든 점 까지의 최단거리 찾기\n  * `A` [프림 알고리즘](src/algorithms/graph/prim) - 무방향 가중치 그래프에서 최소 신창 트리 (MST) 찾기\n  * `A` [크루스칼 알고리즘](src/algorithms/graph/kruskal) - 무방향 가중치 그래프에서 최소 신창 트리 (MST) 찾기\n* **분할 정복법(Divide and Conquer)** - 문제를 여러 작은 문제로 분할한 뒤 해결하는 방식입니다.\n  * `B` [이진 탐색](src/algorithms/search/binary-search)\n  * `B` [하노이 탑](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [파스칼 삼각형](src/algorithms/math/pascal-triangle)\n  * `B` [유클리드 호제법](src/algorithms/math/euclidean-algorithm) - 최대공약수 계산 (GCD)\n  * `B` [병합 정렬](src/algorithms/sorting/merge-sort)\n  * `B` [퀵 정렬](src/algorithms/sorting/quick-sort)\n  * `B` [트리 깊이 우선 탐색](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [그래프 깊이 우선 탐색](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)\n  * `A` [순열](src/algorithms/sets/permutations) (반복 유,무)\n  * `A` [조합](src/algorithms/sets/combinations) (반복 유,무)\n* **동적 계획법(Dynamic Programming)** - 이전에 찾은 결과를 이용하여 최종적으로 해결하는 방식입니다.\n  * `B` [피보나치 수](src/algorithms/math/fibonacci)\n  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  * `B` [빗물 담기 문제](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem\n  * `A` [편집 거리](src/algorithms/string/levenshtein-distance) - 두 시퀀스 간의 최소 편집 거리\n  * `A` [최장 공통 부분 수열](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [최장 공통 부분 문자열](src/algorithms/string/longest-common-substring)\n  * `A` [최장 증가 수열](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [0/1 배낭 문제](src/algorithms/sets/knapsack-problem)\n  * `A` [자연수 분할](src/algorithms/math/integer-partition)\n  * `A` [최대 구간합](src/algorithms/sets/maximum-subarray)\n  * `A` [벨만-포드 알고리즘](src/algorithms/graph/bellman-ford) - 모든 점 까지의 최단 거리 찾기\n  * `A` [플로이드-워셜 알고리즘](src/algorithms/graph/floyd-warshall) - 모든 종단 간의 최단거리 찾기\n  * `A` [정규 표현식 매칭](src/algorithms/string/regular-expression-matching)\n* **백트래킹(Backtracking)** - 모든 가능한 경우를 고려한다는 점에서 브루트 포스와 유사합니다. 하지만 다음 단계로 넘어갈때 마다 모든 조건을 만족했는지 확인하고 진행합니다. 만약 조건을 만족하지 못했다면 뒤로 돌아갑니다 (백트래킹). 그리고 다른 경로를 선택합니다. 보통 상태를  유지한 DFS 탐색을 많이 사용합니다.\n  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  * `A` [해밀턴 경로](src/algorithms/graph/hamiltonian-cycle) - 모든 점을 한번씩 방문\n  * `A` [N-Queens 문제](src/algorithms/uncategorized/n-queens)\n  * `A` [기사의 여행](src/algorithms/uncategorized/knight-tour)\n  * `A` [조합 합](src/algorithms/sets/combination-sum) - 특정 합을 구성하는 모든 조합 찾기\n* **분기 한정법** - 백트래킹으로 찾은 각 단계의 최소 비용이 드는 해를 기억해 두고 있다가, 이 비용을 이용해서 더 낮은 최적의 해를 찾습니다. 기억해둔 최소 비용들을 이용해 더 높은 비용이 드는 해결법을 탐색 안함으로써 불필요한 시간 소모를 줄입니다. 보통 상태 공간 트리의 DFS 탐색을 이용한 BFS 탐색 방식에서 사용됩니다.\n\n## 이 저장소의 사용법\n\n**모든 종속 모듈들 설치**\n```\nnpm install\n```\n\n**ESLint 실행**\n\n코드의 품질을 확인 할 수 있습니다.\n\n```\nnpm run lint\n```\n\n**모든 테스트 실행**\n```\nnpm test\n```\n\n**이름을 통해 특정 테스트 실행**\n```\nnpm test -- 'LinkedList'\n```\n\n**Playground**\n\n `./src/playground/playground.js` 파일을 통해 자료 구조와 알고리즘을 작성하고 `./src/playground/__test__/playground.test.js`에 테스트를 작성할 수 있습니다.\n\n그리고 간단하게 아래 명령어를 통해 의도한대로 동작하는지 확인 할 수 있습니다.:\n\n```\nnpm test -- 'playground'\n```\n\n## 유용한 정보\n\n### 참고\n\n[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Big O 표기\n\nBig O 표기로 표시한 알고리즘의 증가 양상입니다.\n\n![Big O graphs](./assets/big-o-graph.png)\n\nSource: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\n아래는 가장 많이 사용되는 Big O 표기와 입력 데이터 크기에 따른 성능을 비교한 표입니다.\n\n| Big O 표기 | 10 개 일때 | 100 개 일때 | 1000 개 일때  |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### 자료 구조 작업별 복잡도\n\n| 자료 구조                 | 접근       | 검색      | 삽입       | 삭제      | 비고       |\n| ------------------------ | :-------: | :-------: | :-------: | :-------: | :-------- |\n| **배열**                  | 1         | n         | n         | n         |           |\n| **스택**                  | n         | n         | 1         | 1         |           |\n| **큐**                    | n         | n         | 1         | 1         |           |\n| **연결 리스트**            | n         | n         | 1         | 1         |           |\n| **해시 테이블**            | -         | n         | n         | n         | 완벽한 해시 함수의 경우 O(1) |\n| **이진 탐색 트리**          | n         | n         | n         | n         | 균형 트리의 경우 O(log(n)) |\n| **B-트리**                | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Red-Black 트리**        | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **AVL 트리**              | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Bloom Filter**          | -         | 1         | 1         | -         | 거짓 양성이 탐색 중 발생 가능 |\n\n### 정렬 알고리즘 복잡도\n\n| 이름                   | 최적            | 평균                 | 최악                | 메모리     | 동일값 순서유지    | 비고       |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :--------------: | :-------- |\n| **거품 정렬**          | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes              |           |\n| **삽입 정렬**          | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes              |           |\n| **선택 정렬**          | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No               |           |\n| **힙 정렬**            | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No               |           |\n| **병합 정렬**          | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes              |           |\n| **퀵 정렬**            | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No               | 퀵 정렬은 보통 제자리(in-place)로 O(log(n)) 스택공간으로 수행됩니다. |\n| **셸 정렬**            | n&nbsp;log(n)   | 간격 순서에 영향을 받습니다.   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |\n| **계수 정렬**          | n + r           | n + r               | n + r               | n + r     | Yes              | r - 배열내 가장 큰 수 |\n| **기수 정렬**          | n * k           | n * k               | n * k               | n + k     | Yes              | k - 키값의 최대 길이 |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.md",
    "content": "# JavaScript Algorithms and Data Structures\n\n> 🇺🇦 UKRAINE [IS BEING ATTACKED](https://war.ukraine.ua/) BY RUSSIAN ARMY. CIVILIANS ARE GETTING KILLED. RESIDENTIAL AREAS ARE GETTING BOMBED.\n> - Help Ukraine via:\n>   - [Serhiy Prytula Charity Foundation](https://prytulafoundation.org/en/)\n>   - [Come Back Alive Charity Foundation](https://savelife.in.ua/en/donate-en/)\n>   - [National Bank of Ukraine](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi)\n> - More info on [war.ukraine.ua](https://war.ukraine.ua/) and [MFA of Ukraine](https://twitter.com/MFA_Ukraine)\n\n<hr/>\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n![repo size](https://img.shields.io/github/repo-size/trekhleb/javascript-algorithms.svg)\n\nThis repository contains JavaScript based examples of many\npopular algorithms and data structures.\n\nEach algorithm and data structure has its own separate README\nwith related explanations and links for further reading (including ones\nto YouTube videos).\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türkçe_](README.tr-TR.md),\n[_Italiano_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md),\n[_עברית_](README.he-IL.md)\n\n## Data Structures\n\nA data structure is a particular way of organizing and storing data in a computer so that it can\nbe accessed and modified efficiently. More precisely, a data structure is a collection of data\nvalues, the relationships among them, and the functions or operations that can be applied to\nthe data.\n\nRemember that each data has its own trade-offs. And you need to pay attention more to why you're choosing a certain data structure than to how to implement it.\n\n`B` - Beginner, `A` - Advanced\n\n* `B` [Linked List](src/data-structures/linked-list)\n* `B` [Doubly Linked List](src/data-structures/doubly-linked-list)\n* `B` [Queue](src/data-structures/queue)\n* `B` [Stack](src/data-structures/stack)\n* `B` [Hash Table](src/data-structures/hash-table)\n* `B` [Heap](src/data-structures/heap) - max and min heap versions\n* `B` [Priority Queue](src/data-structures/priority-queue)\n* `A` [Trie](src/data-structures/trie)\n* `A` [Tree](src/data-structures/tree)\n  * `A` [Binary Search Tree](src/data-structures/tree/binary-search-tree)\n  * `A` [AVL Tree](src/data-structures/tree/avl-tree)\n  * `A` [Red-Black Tree](src/data-structures/tree/red-black-tree)\n  * `A` [Segment Tree](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples\n  * `A` [Fenwick Tree](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)\n* `A` [Graph](src/data-structures/graph) (both directed and undirected)\n* `A` [Disjoint Set](src/data-structures/disjoint-set) - a union–find data structure or merge–find set\n* `A` [Bloom Filter](src/data-structures/bloom-filter)\n* `A` [LRU Cache](src/data-structures/lru-cache/) - Least Recently Used (LRU) cache\n\n## Algorithms\n\nAn algorithm is an unambiguous specification of how to solve a class of problems. It is\na set of rules that precisely define a sequence of operations.\n\n`B` - Beginner, `A` - Advanced\n\n### Algorithms by Topic\n\n* **Math**\n  * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc.\n  * `B` [Binary Floating Point](src/algorithms/math/binary-floating-point) - binary representation of the floating-point numbers.\n  * `B` [Factorial](src/algorithms/math/factorial)\n  * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions\n  * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem\n  * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method)\n  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)\n  * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM)\n  * `B` [Sieve of Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit\n  * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms)\n  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)\n  * `B` [Complex Number](src/algorithms/math/complex-number) - complex numbers and basic operations with them\n  * `B` [Radian & Degree](src/algorithms/math/radian) - radians to degree and backwards conversion\n  * `B` [Fast Powering](src/algorithms/math/fast-powering)\n  * `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation\n  * `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.)\n  * `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - distance between two points/vectors/matrices\n  * `A` [Integer Partition](src/algorithms/math/integer-partition)\n  * `A` [Square Root](src/algorithms/math/square-root) - Newton's method\n  * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons\n  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up\n* **Sets**\n  * `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets\n  * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence\n  * `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bitwise, backtracking, and cascading solutions)\n  * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)\n  * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)\n  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Knapsack Problem](src/algorithms/sets/knapsack-problem) - \"0/1\" and \"Unbound\" ones\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) - \"Brute Force\" and \"Dynamic Programming\" (Kadane's) versions\n  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum\n* **Strings**\n  * `B` [Hamming Distance](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different\n  * `B` [Palindrome](src/algorithms/string/palindrome) - check if the string is the same in reverse\n  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences\n  * `A` [Knuth–Morris–Pratt Algorithm](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - substring search (pattern matching)\n  * `A` [Z Algorithm](src/algorithms/string/z-algorithm) - substring search (pattern matching)\n  * `A` [Rabin Karp Algorithm](src/algorithms/string/rabin-karp) - substring search\n  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)\n  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)\n* **Searches**\n  * `B` [Linear Search](src/algorithms/search/linear-search)\n  * `B` [Jump Search](src/algorithms/search/jump-search) (or Block Search) - search in sorted array\n  * `B` [Binary Search](src/algorithms/search/binary-search) - search in sorted array\n  * `B` [Interpolation Search](src/algorithms/search/interpolation-search) - search in uniformly distributed sorted array\n* **Sorting**\n  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)\n  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)\n  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)\n  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations\n  * `B` [Shellsort](src/algorithms/sorting/shell-sort)\n  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)\n  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)\n  * `B` [Bucket Sort](src/algorithms/sorting/bucket-sort)\n* **Linked Lists**\n  * `B` [Straight Traversal](src/algorithms/linked-list/traversal)\n  * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)\n* **Trees**\n  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)\n* **Graphs**\n  * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest paths to all graph vertices from single vertex\n  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest paths to all graph vertices from single vertex\n  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices\n  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions)\n  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n  * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS method\n  * `A` [Articulation Points](src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based)\n  * `A` [Bridges](src/algorithms/graph/bridges) - DFS based algorithm\n  * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once\n  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once\n  * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm\n  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city\n* **Cryptography**\n  * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial\n  * `B` [Rail Fence Cipher](src/algorithms/cryptography/rail-fence-cipher) - a transposition cipher algorithm for encoding messages\n  * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher\n  * `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - substitution cipher based on linear algebra\n* **Machine Learning**\n  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation)\n  * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm\n  * `B` [k-Means](src/algorithms/ml/k-means) - k-Means clustering algorithm\n* **Image Processing**\n  * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm\n* **Statistics**\n  * `B` [Weighted Random](src/algorithms/statistics/weighted-random) - select the random item from the list based on items' weights\n* **Evolutionary algorithms**\n  * `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\n* **Uncategorized**\n  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions)\n  * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples\n  * `B` [Valid Parentheses](src/algorithms/stack/valid-parentheses) - check if a string has valid parentheses (using stack)\n  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n\n### Algorithms by Paradigm\n\nAn algorithmic paradigm is a generic method or approach which underlies the design of a class\nof algorithms. It is an abstraction higher than the notion of an algorithm, just as an\nalgorithm is an abstraction higher than a computer program.\n\n* **Brute Force** - look at all the possibilities and selects the best solution\n  * `B` [Linear Search](src/algorithms/search/linear-search)\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach the top\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)\n  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city\n  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up\n* **Greedy** - choose the best option at the current time, without any consideration for the future\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem)\n  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest path to all graph vertices\n  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n* **Divide and Conquer** - divide the problem into smaller parts and then solve those parts\n  * `B` [Binary Search](src/algorithms/search/binary-search)\n  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)\n  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort)\n  * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different shapes\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Fast Powering](src/algorithms/math/fast-powering)\n  * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples\n  * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)\n  * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)\n* **Dynamic Programming** - build up a solution using previously found sub-solutions\n  * `B` [Fibonacci Number](src/algorithms/math/fibonacci)\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach the top\n  * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm\n  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences\n  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)\n  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem)\n  * `A` [Integer Partition](src/algorithms/math/integer-partition)\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)\n  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest path to all graph vertices\n  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices\n  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)\n* **Backtracking** - similarly to brute force, try to generate all possible solutions, but each time you generate the next solution, you test\nif it satisfies all conditions and only then continue generating subsequent solutions. Otherwise, backtrack and go on a\ndifferent path to finding a solution. Normally the DFS traversal of state-space is being used.\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  * `B` [Power Set](src/algorithms/sets/power-set) - all subsets of a set\n  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once\n  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum\n* **Branch & Bound** - remember the lowest-cost solution found at each stage of the backtracking\nsearch, and use the cost of the lowest-cost solution found so far as a lower bound on the cost of\na least-cost solution to the problem in order to discard partial solutions with costs larger than the\nlowest-cost solution found so far. Normally, BFS traversal in combination with DFS traversal of state-space\ntree is being used.\n\n## How to use this repository\n\n**Install all dependencies**\n\n```\nnpm install\n```\n\n**Run ESLint**\n\nYou may want to run it to check code quality.\n\n```\nnpm run lint\n```\n\n**Run all tests**\n\n```\nnpm test\n```\n\n**Run tests by name**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**Troubleshooting**\n\nIf linting or testing is failing, try to delete the `node_modules` folder and re-install npm packages:\n\n```\nrm -rf ./node_modules\nnpm i\n```\n\nAlso, make sure that you're using the 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.\n\n**Playground**\n\nYou may play with data-structures and algorithms in `./src/playground/playground.js` file and write\ntests for it in `./src/playground/__test__/playground.test.js`.\n\nThen just, simply run the following command to test if your playground code works as expected:\n\n```\nnpm test -- 'playground'\n```\n\n## Useful Information\n\n### References\n\n- [▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [✍🏻 Data Structure Sketches](https://okso.app/showcase/data-structures)\n\n### Big O Notation\n\n*Big O notation* is used to classify algorithms according to how their running time or space requirements grow as the input size grows.\nOn the chart below, you may find the most common orders of growth of algorithms specified in Big O notation.\n\n![Big O graphs](./assets/big-o-graph.png)\n\nSource: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nBelow is the list of some of the most used Big O notations and their performance comparisons against different sizes of the input data.\n\n| Big O Notation | Type        | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements  |\n| -------------- | ----------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | Constant    | 1                            | 1                             | 1                               |\n| **O(log N)**   | Logarithmic | 3                            | 6                             | 9                               |\n| **O(N)**       | Linear      | 10                           | 100                           | 1000                            |\n| **O(N log N)** | n log(n)    | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | Quadratic   | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | Exponential | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | Factorial   | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### Data Structure Operations Complexity\n\n| Data Structure          | Access    | Search    | Insertion | Deletion  | Comments  |\n| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |\n| **Array**               | 1         | n         | n         | n         |           |\n| **Stack**               | n         | n         | 1         | 1         |           |\n| **Queue**               | n         | n         | 1         | 1         |           |\n| **Linked List**         | n         | n         | 1         | n         |           |\n| **Hash Table**          | -         | n         | n         | n         | In case of perfect hash function costs would be O(1) |\n| **Binary Search Tree**  | n         | n         | n         | n         | In case of balanced tree costs would be O(log(n)) |\n| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Bloom Filter**        | -         | 1         | 1         | -         | False positives are possible while searching |\n\n### Array Sorting Algorithms Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |\n| **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 |\n| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - biggest number in array |\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - length of longest key |\n\n## Project Backers\n\n> You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n[Folks who are backing this project](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`\n\n## Author\n\n[@trekhleb](https://trekhleb.dev)\n\nA few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.pl-PL.md",
    "content": "# JavaScript Algorytmy i Struktury Danych\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nTo repozytorium zawiera wiele przykładów JavaScript opartych na\nznanych algorytmach i strukturach danych.\n\nKażdy algorytm i struktura danych zawiera osobny plik README\nwraz z powiązanymi wyjaśnieniami i odnośnikami do dalszego czytania\n(włącznie z tymi do YouTube videos).\n\n_Read this in other languages:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/)\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Struktury Danych\n\nStruktura danych to sposób uporządkowania i przechowywania informacji w\nkomputerze żeby mogłaby być sprawnie dostępna i efektywnie zmodyfikowana.\nDokładniej, struktura danych jest zbiorem wartości danych, relacjami\npomiędzy nimi, zadaniami lub działaniami, które mogą dotyczyć danych.\n\n`B` - Początkujący, `A` - Zaawansowany\n\n* `B` [Lista](src/data-structures/linked-list)\n* `B` [Lista Dwukierunkowa](src/data-structures/doubly-linked-list)\n* `B` [Kolejka](src/data-structures/queue)\n* `B` [Stos](src/data-structures/stack)\n* `B` [Tabela Skrótu](src/data-structures/hash-table)\n* `B` [Sterta](src/data-structures/heap)\n* `B` [Kolejka Priorytetowa](src/data-structures/priority-queue)\n* `A` [Trie](src/data-structures/trie)\n* `A` [Drzewo](src/data-structures/tree)\n  * `A` [Wyszukiwanie Binarne](src/data-structures/tree/binary-search-tree)\n  * `A` [AVL Drzewo](src/data-structures/tree/avl-tree)\n  * `A` [Drzewa czerwono-czarne](src/data-structures/tree/red-black-tree)\n  * `A` [Drzewo Segmentu](src/data-structures/tree/segment-tree) - z przykładami zapytań o min / max / sumie sum\n  * `A` [Drzewo Fenwicka](src/data-structures/tree/fenwick-tree) (Drzewo Indeksowane Binarnie)\n* `A` [Graf](src/data-structures/graph) (zarówno skierowane i nieukierunkowane)\n* `A` [Rozłączny Zestaw](src/data-structures/disjoint-set)\n* `A` [Filtr Blooma](src/data-structures/bloom-filter)\n\n## Algorytmy\n\nAlgorytm jest to skończony ciąg jasno zdefiniowanych czynności, koniecznych\ndo wykonania pewnego rodzaju zadań. Sposób postępowania prowadzący do\nrozwiązania problemu.\n\n`B` - Początkujący, `A` - Zaawansowany\n\n### Algorytmy według tematu\n\n* **Matematyka**\n  * `B` [Manipulacja Bitami](src/algorithms/math/bits) - ustaw / uzyskaj / aktualizuj / usuwaj bity, mnożenie / dzielenie przez dwa, tworzenie negatywów itp.\n  * `B` [Silnia](src/algorithms/math/factorial)\n  * `B` [Ciąg Fibonacciego](src/algorithms/math/fibonacci)\n  * `B` [Test Pierwszorzędności](src/algorithms/math/primality-test) (metoda podziału na próby)\n  * `B` [Algorytm Euclideana](src/algorithms/math/euclidean-algorithm) - obliczyć Największy Wspólny Dzielnik (GCD)\n  * `B` [Najmniejsza Wspólna Wielokrotność](src/algorithms/math/least-common-multiple) (LCM)\n  * `B` [Sito Eratosthenes-a](src/algorithms/math/sieve-of-eratosthenes) - znajdowanie wszystkich liczb pierwszych do określonego limitu\n  * `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)\n  * `B` [Trójkąt Pascala](src/algorithms/math/pascal-triangle)\n  * `A` [Partycja Całkowita](src/algorithms/math/integer-partition)\n  * `A` [Algorytm Liu Huia](src/algorithms/math/liu-hui) - przybliżone obliczenia na podstawie N-gonów\n* **Zestawy**\n  * `B` [Produkt Kartezyjny](src/algorithms/sets/cartesian-product) - wynik wielu zestawów\n  * `B` [Przetasowanie Fisher Yates-a](src/algorithms/sets/fisher-yates) - losowa permutacja kończącej się serii\n  * `A` [Zestaw Zasilający](src/algorithms/sets/power-set) - podzbiór wszystkich serii\n  * `A` [Permutacje](src/algorithms/sets/permutations) (z albo bez powtórzeń)\n  * `A` [Kombinacje](src/algorithms/sets/combinations) (z albo bez powtórzeń)\n  * `A` [Najdłuższa Wspólna Podsekwencja](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Najdłuższa Wzrostająca Podsekwencja](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Najkrótsza Wspólna Supersekwencja](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Problem Knapsacka](src/algorithms/sets/knapsack-problem) - \"0/1\" i \"Rozwiązany\"\n  * `A` [Maksymalna Podtablica](src/algorithms/sets/maximum-subarray) - \"Metoda Siłowa\" i \"Dynamiczne Programowanie\" (Kadane-a) wersje\n  * `A` [Suma Kombinacji](src/algorithms/sets/combination-sum) -\nznajdź wszystkie kombinacje, które tworzą określoną sumę\n* **Łańcuchy**\n  * `B` [Odległość Hamminga](src/algorithms/string/hamming-distance) - liczba pozycji, w których symbole są różne\n  * `A` [Odległość Levenshteina](src/algorithms/string/levenshtein-distance) - minimalna odległość edycji między dwiema sekwencjami\n  * `A` [Algorytm Knuth–Morris–Pratta](src/algorithms/string/knuth-morris-pratt) (Algorytm KMP) - dopasowywanie wzorców (dopasowywanie wzorców)\n  * `A` [Algorytm Z](src/algorithms/string/z-algorithm) - szukanie podłańcucha(dopasowywanie wzorców)\n  * `A` [Algorytm Rabin Karpa](src/algorithms/string/rabin-karp) - szukanie podłańcucha\n  * `A` [Najdłuższa Wspólna Podłańcucha](src/algorithms/string/longest-common-substring)\n  * `A` [Dopasowanie Wyrażeń Regularnych](src/algorithms/string/regular-expression-matching)\n* **Szukanie**\n  * `B` [Wyszukiwanie Liniowe](src/algorithms/search/linear-search)\n  * `B` [Jump Search](src/algorithms/search/jump-search) (lub Przeszukiwanie Bloku) - szukaj w posortowanej tablicy\n  * `B` [Wyszukiwanie Binarne](src/algorithms/search/binary-search) - szukaj w posortowanej tablicy\n  * `B` [Wyszukiwanie Interpolacyjne](src/algorithms/search/interpolation-search) - szukaj w równomiernie rozłożonej, posortowanej tablicy\n* **Sortowanie**\n  * `B` [Sortowanie bąbelkowe](src/algorithms/sorting/bubble-sort)\n  * `B` [Sortowanie przez wymiane](src/algorithms/sorting/selection-sort)\n  * `B` [Sortowanie przez wstawianie](src/algorithms/sorting/insertion-sort)\n  * `B` [Sortowanie stogowe](src/algorithms/sorting/heap-sort)\n  * `B` [Sortowanie przez scalanie](src/algorithms/sorting/merge-sort)\n  * `B` [Sortowanie szybkie](src/algorithms/sorting/quick-sort) - wdrożenia w miejscu i nie na miejscu\n  * `B` [Sortowanie Shella](src/algorithms/sorting/shell-sort)\n  * `B` [Sortowanie przez zliczanie](src/algorithms/sorting/counting-sort)\n  * `B` [Sortowanie pozycyjne](src/algorithms/sorting/radix-sort)\n* **Drzewa**\n  * `B` [Przeszukiwanie w głąb](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Przeszukiwanie wszerz](src/algorithms/tree/breadth-first-search) (BFS)\n* **Grafy**\n  * `B` [Przeszukiwanie w głąb](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Przeszukiwanie wszerz](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Algorytm Kruskala](src/algorithms/graph/kruskal) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu\n  * `A` [Algorytm Dijkstry](src/algorithms/graph/dijkstra) - znajdowanie  najkrótszej ścieżki z pojedynczego źródła w grafie\n  * `A` [Algorytm Bellmana-Forda](src/algorithms/graph/bellman-ford) - znajdowanie najkrótszych ścieżek do wszystkich wierzchołków wykresu z jednego wierzchołka\n  * `A` [Algorytm Floyd-Warshalla](src/algorithms/graph/floyd-warshall) - znajdź najkrótsze ścieżki między wszystkimi parami wierzchołków\n  * `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)\n  * `A` [Algorytm Prima](src/algorithms/graph/prim) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu\n  * `A` [Sortowanie Topologiczne](src/algorithms/graph/topological-sorting) - metoda DFS\n  * `A` [Punkty Artykulacji](src/algorithms/graph/articulation-points) - Algorytm Tarjana (oparty o DFS)\n  * `A` [Mosty](src/algorithms/graph/bridges) - Oparty na algorytmie DFS\n  * `A` [Ścieżka Euleriana i Obwód Euleriana](src/algorithms/graph/eulerian-path) - Algorytm Fleurya - Odwiedź każdą krawędź dokładnie raz\n  * `A` [Cykl Hamiltoniana](src/algorithms/graph/hamiltonian-cycle) - Odwiedź każdy wierzchołek dokładnie raz\n  * `A` [Silnie Połączone Komponenty](src/algorithms/graph/strongly-connected-components) - Algorytm Kosaraja\n  * `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\n* **Niezkategorizowane**\n  * `B` [Wieża Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Kwadratowa Matryca Obrotu](src/algorithms/uncategorized/square-matrix-rotation) - algorytm w miejscu\n  * `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\n  * `B` [Unikatowe Ścieżki](src/algorithms/uncategorized/unique-paths) - cofanie, dynamiczne programowanie i przykłady oparte na Trójkącie Pascala\n  * `A` [Problem N-Queens](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n\n### Algorytmy według paradygmatu\n\nParadygmat algorytmiczny jest ogólną metodą lub podejściem, które jest\npodstawą projektowania klasy algorytmów. Jest abstrakcją wyższą niż\npojęcie algorytmu, podobnie jak algorytm jest abstrakcją wyższą niż\nprogram komputerowy.\n\n* **Metoda Siłowa** - Sprawdza wszystkie możliwosci i wybiera  najlepsze rozwiązanie.\n  * `B` [Wyszukiwanie Liniowe](src/algorithms/search/linear-search)\n  * `A` [Maksymalna Podtablica](src/algorithms/sets/maximum-subarray)\n  * `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\n* **Chciwy** - wybierz najlepszą opcję w obecnym czasie, bez względu na przyszłość\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `A` [Niezwiązany Problem Knapsacka ](src/algorithms/sets/knapsack-problem)\n  * `A` [Algorytm Dijkstry](src/algorithms/graph/dijkstra) -\nznalezienie najkrótszej ścieżki do wszystkich wierzchołków grafu\n  * `A` [Algorytm Prima](src/algorithms/graph/prim) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu\n  * `A` [Algorytm Kruskala](src/algorithms/graph/kruskal) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu\n* **Dziel i Zwyciężaj** - podziel problem na mniejsze części, a następnie rozwiąż te części\n  * `B` [Wyszukiwanie Binarne](src/algorithms/search/binary-search)\n  * `B` [Wieża Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Trójkąt Pascala](src/algorithms/math/pascal-triangle)\n  * `B` [Algorytm Euclideana](src/algorithms/math/euclidean-algorithm) - obliczyć Największy Wspólny Dzielnik(GCD)\n  * `B` [Sortowanie przez scalanie](src/algorithms/sorting/merge-sort)\n  * `B` [Szybkie Sortowanie](src/algorithms/sorting/quick-sort)\n  * `B` [Drzewo Przeszukiwania W Głąb](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Graf Przeszukiwania W Głąb](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `A` [Permutacje](src/algorithms/sets/permutations) (z albo bez powtórzeń)\n  * `A` [Kombinacje](src/algorithms/sets/combinations) (z albo bez powtórzeń)\n* **Programowanie Dynamiczne** - zbuduj rozwiązanie, korzystając z wcześniej znalezionych podrzędnych rozwiązań\n  * `B` [Ciąg Fibonacciego](src/algorithms/math/fibonacci)\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Unikatowe Scieżki](src/algorithms/uncategorized/unique-paths)\n  * `A` [Dystans Levenshteina](src/algorithms/string/levenshtein-distance) - minimalna odległość edycji między dwiema sekwencjami\n  * `A` [Najdłuższa Wspólna Podsekwencja](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Najdłuższa Wspólna Podłańcucha](src/algorithms/string/longest-common-substring)\n  * `A` [Najdłuższa Wzrostająca Podsekwencja](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Najkrótsza Wspólna Supersekwencja](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [0/1 Problem Knapsacka](src/algorithms/sets/knapsack-problem)\n  * `A` [Partycja Całkowita](src/algorithms/math/integer-partition)\n  * `A` [Maksymalne Podtablice](src/algorithms/sets/maximum-subarray)\n  * `A` [Algorytm Bellman-Forda](src/algorithms/graph/bellman-ford) - znalezienie najkrótszej ścieżki wszystkich wierzchołków wykresu\n  * `A` [Algorytm Floyd-Warshalla](src/algorithms/graph/floyd-warshall) -\nznajdź najkrótsze ścieżki między wszystkimi parami wierzchołków\n  * `A` [Dopasowanie Wyrażeń Regularnych](src/algorithms/string/regular-expression-matching)\n* **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\njeż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.\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Unikatowe Scieżki](src/algorithms/uncategorized/unique-paths)\n  * `A` [Cykl Hamiltoniana](src/algorithms/graph/hamiltonian-cycle) - Odwiedź każdy wierzchołek dokładnie raz\n  * `A` [Problem N-Queens](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n  * `A` [Zestaw Sumy](src/algorithms/sets/combination-sum) - znajduje wszystkie zestawy które tworzą określoną sumę\n* **Metoda Podziału i Ograniczeń** - Pamięta o niskonakładowym rozwiązaniu znalezionym na każdym etapie szukania nawrotu,\nużywa kosztu niskonakładowego kosztu, które dotychczas zostało znalezione jako niska granica najmniejszego kosztu\ndo rozwiązanie problemu, aby odrzucić cząstkowe rozwiązania o kosztach większych niż niskonakładowe\nrozwiązanie znalezione do tej pory.\nZazwyczan trajektoria BFS, w połączeniu z trajektorią Przeszukiwania W Głąb (DFS) drzewa przestrzeni stanów jest użyte.\n\n## Jak używać repozytorium\n\n**Zainstaluj wszystkie zależnosci**\n```\nnpm install\n```\n\n**Uruchom ESLint**\n\nMożesz to uruchomić aby sprawdzić jakość kodu.\n\n```\nnpm run lint\n```\n\n**Uruchom wszystkie testy**\n```\nnpm test\n```\n\n**Uruchom testy używając określonej nazwy**\n```\nnpm test -- 'LinkedList'\n```\n\n**Playground**\n\nMożesz pociwiczyć ze strukturą danych i algorytmami w `./src/playground/playground.js` zakartotekuj i napisz\ntesty do tego w `./src/playground/__test__/playground.test.js`.\n\nNastępnie uruchom następującą komendę w celu przetestowania czy twoje kod działa według oczekiwań:\n\n```\nnpm test -- 'playground'\n```\n\n## Pomocne informacje\n\n### Źródła\n\n[â–¶ Struktury Danych i Algorytmy na YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Big O Notacja\n\nKolejność wzrastania algorytmów według Big O notacji.\n\n![Big O grafy](./assets/big-o-graph.png)\n\nŹródło: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nPoniżej umieszczamy listę najbardziej używanych Big O notacji i ich porównania wydajności do róznych rozmiarów z wprowadzonych danych.\n\n| Big O notacja  | Obliczenia na 10 elementów   | Obliczenia na 100 elementów   | Obliczenia na 1000 elementów    |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### Złożoność operacji struktury danych\n\n| Struktura Danych                | Dostęp    | Szukaj    | Umieszczanie | Usuwanie  | Komentarze   |\n| ------------------------------- | :-------: | :-------: | :----------: | :-------: | :----------- |\n| **Szereg**                      | 1         | n         | n            | n         |              |\n| **Sterta**                      | n         | n         | 1            | 1         |              |\n| **Kolejka**                     | n         | n         | 1            | 1         |              |\n| **Lista Powiązana**             | n         | n         | 1            | 1         |              |\n| **Tablica funkcji mieszanej**   | -         | n         | n            | n         | W wypadku idealnej funkcji skrótu koszt mógłby sie równać O(1) |\n| **Binarne Drzewo Poszukiwań**   | n         | n         | n            | n         | W przypadku zrównoważonych kosztów drzew byłoby O(log(n)) |\n| **B-Drzewo**                    | log(n)    | log(n)    | log(n)       | log(n)    |              |\n| **Drzewa czerwono-czarne**      | log(n)    | log(n)    | log(n)       | log(n)    |              |\n| **AVL Drzewo**                  | log(n)    | log(n)    | log(n)       | log(n)    |              |\n| **Filtr Blooma**                | -         | 1         | 1            | -         | Fałszywe dotatnie są możliwe podczas wyszukiwania |\n\n### Sortowanie Tablic Złożoności Algorytmów\n\n| Nazwa                               | Najlepszy       | Średni              | Najgorszy           | Pamięć    | Stabilność  | Komentarze  |\n| ----------------------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :---------: | :---------- |\n| **Sortowanie bąbelkowe**            | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes         |             |\n| **Sortowanie przez wstawianie**     | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes         |             |\n| **Sortowanie przez wybieranie**     | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No          |             |\n| **Sortowanie przez kopcowanie**     | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No          |             |\n| **Sortowanie przez scalanie**       | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes         |             |\n| **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 |\n| **Sortowanie Shella**               | n&nbsp;log(n)   | zależy od luki w układzie   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |\n| **Sortowanie przez zliczanie**      | n + r           | n + r               | n + r               | n + r     | Yes         | r - największy numer w tablicy|\n| **Sortowanie Radix**                | n * k           | n * k               | n * k               | n + k     | Yes         | k -długość najdłuższego klucza |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.pt-BR.md",
    "content": "# Estrutura de Dados e Algoritmos em JavaScript\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nEste repositório contém exemplos baseados em JavaScript de muitos\nalgoritmos e estruturas de dados populares.\n\nCada algoritmo e estrutura de dados possui seu próprio README\ncom explicações relacionadas e links para leitura adicional (incluindo\nvídeos para YouTube)\n\n_Leia isto em outros idiomas:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/)\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Estrutura de Dados\n\nUma estrutura de dados é uma maneira particular de organizar e armazenar dados em um computador para que ele possa\nser 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.\n\n`B` - Iniciante, `A` - Avançado\n\n* `B` [Lista Encadeada (Linked List)](src/data-structures/linked-list/README.pt-BR.md)\n* `B` [Lista Duplamente Ligada (Doubly Linked List)](src/data-structures/doubly-linked-list/README.pt-BR.md)\n* `B` [Fila (Queue)](src/data-structures/queue/README.pt-BR.md)\n* `B` [Pilha (Stack)](src/data-structures/stack/README.pt-BR.md)\n* `B` [Tabela de Hash (Hash Table)](src/data-structures/hash-table/README.pt-BR.md)\n* `B` [Heap](src/data-structures/heap/README.pt-BR.md) - versões de heap máximo e mínimo\n* `B` [Fila de Prioridade (Priority Queue)](src/data-structures/priority-queue/README.pt-BR.md)\n* `A` [Árvore de Prefixos (Trie)](src/data-structures/trie/README.pt-BR.md)\n* `A` [Árvore (Tree)](src/data-structures/tree/README.pt-BR.md)\n  * `A` [Árvore de Pesquisa Binária (Binary Search Tree)](src/data-structures/tree/binary-search-tree/README.pt-BR.md)\n  * `A` [Árvore AVL (AVL Tree)](src/data-structures/tree/avl-tree/README.pt-BR.md)\n  * `A` [Árvore Rubro-Negra (Red-Black Tree)](src/data-structures/tree/red-black-tree/README.pt-BR.md)\n  * `A` [Árvore de Segmento (Segment Tree)](src/data-structures/tree/segment-tree/README.pt-BR.md) - com exemplos de consultas min / max / sum range\n  * `A` [Árvore Fenwick (Fenwick Tree)](src/data-structures/tree/fenwick-tree/README.pt-BR.md) (Árvore indexada binária)\n* `A` [Grafo (Graph)](src/data-structures/graph/README.pt-BR.md) (ambos dirigidos e não direcionados)\n* `A` [Conjunto Disjunto (Disjoint Set)](src/data-structures/disjoint-set/README.pt-BR.md)\n* `A` [Filtro Bloom (Bloom Filter)](src/data-structures/bloom-filter/README.pt-BR.md)\n\n## Algoritmos\n\nUm algoritmo é uma especificação inequívoca de como resolver uma classe de problemas. Isto é\num conjunto de regras que define precisamente uma sequência de operações.\n\n`B` - Iniciante, `A` - Avançado\n\n### Algoritmos por Tópico\n\n* **Matemática**\n  * `B` [Manipulação Bit](src/algorithms/math/bits) - set/get/update/clear bits, multiplicação / divisão por dois, tornar negativo etc.\n  * `B` [Fatorial](src/algorithms/math/factorial)\n  * `B` [Número de Fibonacci](src/algorithms/math/fibonacci)\n  * `B` [Teste de Primalidade](src/algorithms/math/primality-test) (método de divisão experimental)\n  * `B` [Algoritmo Euclidiano](src/algorithms/math/euclidean-algorithm) - Calcular o Máximo Divisor Comum (MDC)\n  * `B` [Mínimo Múltiplo Comum](src/algorithms/math/least-common-multiple) Calcular o Mínimo Múltiplo Comum (MMC)\n  * `B` [Peneira de Eratóstenes](src/algorithms/math/sieve-of-eratosthenes) - Encontrar todos os números primos até um determinado limite\n  * `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)\n  * `B` [Triângulo de Pascal](src/algorithms/math/pascal-triangle)\n  * `B` [Número Complexo](src/algorithms/math/complex-number) - Números complexos e operações básicas com eles\n  * `A` [Partição Inteira](src/algorithms/math/integer-partition)\n  * `A` [Algoritmo Liu Hui π](src/algorithms/math/liu-hui) - Cálculos aproximados de π baseados em N-gons\n* **Conjuntos**\n  * `B` [Produto Cartesiano](src/algorithms/sets/cartesian-product) - Produto de vários conjuntos\n  * `B` [Permutações de Fisher–Yates](src/algorithms/sets/fisher-yates) - Permutação aleatória de uma sequência finita\n  * `A` [Potência e Conjunto](src/algorithms/sets/power-set) - Todos os subconjuntos de um conjunto\n  * `A` [Permutações](src/algorithms/sets/permutations) (com e sem repetições)\n  * `A` [Combinações](src/algorithms/sets/combinations) (com e sem repetições)\n  * `A` [Mais Longa Subsequência Comum](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Maior Subsequência Crescente](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Supersequência Comum Mais Curta](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Problema da Mochila](src/algorithms/sets/knapsack-problem) - \"0/1\" e \"Não consolidado\"\n  * `A` [Subarray Máximo](src/algorithms/sets/maximum-subarray) - \"Força bruta\" e \"Programação Dinâmica\", versões de Kadane\n  * `A` [Soma de Combinação](src/algorithms/sets/combination-sum) - Encontre todas as combinações que formam uma soma específica\n* **Cadeia de Caracteres**\n  * `B` [Distância de Hamming](src/algorithms/string/hamming-distance) - Número de posições em que os símbolos são diferentes\n  * `B` [Palíndromos](src/algorithms/string/palindrome) - Verifique se a cadeia de caracteres (string) é a mesma ao contrário\n  * `A` [Distância Levenshtein](src/algorithms/string/levenshtein-distance) - Distância mínima de edição entre duas sequências\n  * `A` [Algoritmo Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (Algoritmo KMP) - Pesquisa de substring (correspondência de padrão)\n  * `A` [Z Algorithm](src/algorithms/string/z-algorithm) - Pesquisa de substring (correspondência de padrão)\n  * `A` [Algoritmo de Rabin Karp](src/algorithms/string/rabin-karp) - Pesquisa de substring\n  * `A` [Substring Comum Mais Longa](src/algorithms/string/longest-common-substring)\n  * `A` [Expressões Regulares Correspondentes](src/algorithms/string/regular-expression-matching)\n* **Buscas**\n  * `B` [Busca Linear (Linear Search)](src/algorithms/search/linear-search)\n  * `B` [Busca por Saltos (Jump Search)](src/algorithms/search/jump-search) - Pesquisa em matriz ordenada\n  * `B` [Busca Binária (Binary Search)](src/algorithms/search/binary-search) - Pesquisa em matriz ordenada\n  * `B` [Busca por Interpolação (Interpolation Search)](src/algorithms/search/interpolation-search) - Pesquisa em matriz classificada uniformemente distribuída\n* **Classificação**\n  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)\n  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)\n  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)\n  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - Implementações local e não local\n  * `B` [Shellsort](src/algorithms/sorting/shell-sort)\n  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)\n  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)\n* **Árvores**\n  * `B` [Busca em Profundidade (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Busca em Largura (Breadth-First Search)](src/algorithms/tree/breadth-first-search) (BFS)\n* **Grafos**\n  * `B` [Busca em Profundidade (Depth-First Search)](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Busca em Largura (Breadth-First Search)](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - Encontrando Árvore Mínima de Abrangência (MST) para grafo conexo com pesos\n  * `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\n  * `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\n  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - Encontrar caminhos mais curtos entre todos os pares de vértices\n  * `A` [Detectar Ciclo](src/algorithms/graph/detect-cycle) - Para grafos direcionados e não direcionados (versões baseadas em DFS e Conjunto Disjuntivo)\n  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - Encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado\n  * `A` [Ordenação Topológica](src/algorithms/graph/topological-sorting) - Métodos DFS\n  * `A` [Pontos de Articulação](src/algorithms/graph/articulation-points) - O algoritmo de Tarjan (baseado em DFS)\n  * `A` [Pontes](src/algorithms/graph/bridges) - Algoritmo baseado em DFS\n  * `A` [Caminho e Circuito Euleriano](src/algorithms/graph/eulerian-path) - Algoritmo de Fleury - Visite todas as bordas exatamente uma vez\n  * `A` [Ciclo Hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - Visite todas as bordas exatamente uma vez\n  * `A` [Componentes Fortemente Conectados](src/algorithms/graph/strongly-connected-components) - Algoritmo de Kosaraju\n  * `A` [Problema do Caixeiro Viajante](src/algorithms/graph/travelling-salesman) - Rota mais curta possível que visita cada cidade e retorna à cidade de origem\n* **Criptografia**\n  * `B` [Hash Polinomial](src/algorithms/cryptography/polynomial-hash) - Função de hash de rolagem baseada em polinômio\n* **Sem categoria**\n  * `B` [Torre de Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Rotação de Matriz Quadrada](src/algorithms/uncategorized/square-matrix-rotation) - Algoritmo no local\n  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game) - Backtracking, programação dinâmica (top-down + bottom-up) e exemplos gananciosos\n  * `B` [Caminhos Únicos](src/algorithms/uncategorized/unique-paths) - Backtracking, programação dinâmica e exemplos baseados no triângulo de Pascal\n  * `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)\n  * `A` [Problema das N-Rainhas](src/algorithms/uncategorized/n-queens)\n  * `A` [Passeio do Cavaleiro](src/algorithms/uncategorized/knight-tour)\n\n### Algoritmos por Paradigma\n\nUm paradigma algorítmico é um método ou abordagem genérica subjacente ao design de uma classe\nde algoritmos. É uma abstração maior do que a noção de um algoritmo, assim como\nalgoritmo é uma abstração maior que um programa de computador.\n\n* **Força bruta** - Pense em todas as possibilidades e escolha a melhor solução\n  * `B` [Busca Linear (Linear Search)](src/algorithms/search/linear-search)\n  * `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)\n  * `A` [Subarray Máximo](src/algorithms/sets/maximum-subarray)\n  * `A` [Problema do Caixeiro Viajante](src/algorithms/graph/travelling-salesman) - Rota mais curta possível que visita cada cidade e retorna à cidade de origem\n* **Ganância** - Escolha a melhor opção no momento, sem qualquer consideração pelo futuro\n  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)\n  * `A` [Problema da Mochila](src/algorithms/sets/knapsack-problem)\n  * `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\n  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - Encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado\n  * `A` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - Encontrando Árvore Mínima de Abrangência (MST) para grafo conexo com pesos\n* **Dividir e Conquistar** - Dividir o problema em partes menores e então resolver essas partes\n  * `B` [Busca Binária (Binary Search)](src/algorithms/search/binary-search)\n  * `B` [Torre de Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Triângulo de Pascal](src/algorithms/math/pascal-triangle)\n  * `B` [Algoritmo Euclidiano](src/algorithms/math/euclidean-algorithm) - Calcular o Máximo Divisor Comum (MDC)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort)\n  * `B` [Busca em Profundidade (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Busca em Largura (Breadth-First Search)](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)\n  * `A` [Permutações](src/algorithms/sets/permutations) (com e sem repetições)\n  * `A` [Combinações](src/algorithms/sets/combinations) (com e sem repetições)\n* **Programação Dinâmica** - Criar uma solução usando sub-soluções encontradas anteriormente\n  * `B` [Número de Fibonacci](src/algorithms/math/fibonacci)\n  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)\n  * `B` [Caminhos Únicos](src/algorithms/uncategorized/unique-paths)\n  * `B` [Terraços de Chuva](src/algorithms/uncategorized/rain-terraces) - Trapping problema da água da chuva\n  * `A` [Distância Levenshtein](src/algorithms/string/levenshtein-distance) - Distância mínima de edição entre duas sequências\n  * `A` [Mais Longa Subsequência Comum](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Substring Comum Mais Longa](src/algorithms/string/longest-common-substring)\n  * `A` [Maior Subsequência Crescente](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Supersequência Comum Mais Curta](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Problema da Mochila](src/algorithms/sets/knapsack-problem)\n  * `A` [Partição Inteira](src/algorithms/math/integer-partition)\n  * `A` [Subarray Máximo](src/algorithms/sets/maximum-subarray)\n  * `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\n  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - Encontrar caminhos mais curtos entre todos os pares de vértices\n  * `A` [Expressões Regulares Correspondentes](src/algorithms/string/regular-expression-matching)\n* **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.\n  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)\n  * `B` [Caminhos Únicos](src/algorithms/uncategorized/unique-paths)\n  * `A` [Ciclo Hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - Visite todos os vértices exatamente uma vez\n  * `A` [Problema das N-Rainhas](src/algorithms/uncategorized/n-queens)\n  * `A` [Passeio do Cavaleiro](src/algorithms/uncategorized/knight-tour)\n  * `A` [Soma de Combinação](src/algorithms/sets/combination-sum) - Encontre todas as combinações que formam uma soma específica\n* **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\nsolução de menor custo para o problema, a fim de descartar soluções parciais com custos maiores que o\nsolução de menor custo encontrada até o momento. Normalmente, a travessia BFS em combinação com a passagem DFS do espaço de estados\nárvore está sendo usada\n\n## Como usar este repositório\n\n**Instalar todas as dependências**\n```\nnpm install\n```\n\n**Executar o ESLint**\n\nVocê pode querer executá-lo para verificar a qualidade do código.\n\n```\nnpm run lint\n```\n\n**Execute todos os testes**\n```\nnpm test\n```\n\n**Executar testes por nome**\n```\nnpm test -- 'LinkedList'\n```\n**Solução de problemas**\n\nCaso o linting ou o teste estejam falhando, tente excluir a pasta node_modules e reinstalar os pacotes npm:\n```\nrm -rf ./node_modules\nnpm i\n```\n\nVerifique 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.\n\n**Playground**\n\nVocê pode brincar com estruturas de dados e algoritmos no arquivo `./src/playground/playground.js` e escrever\ntestes para isso em `./src/playground/__test__/playground.test.js`.\n\nEm seguida, basta executar o seguinte comando para testar se o código do seu playground funciona conforme o esperado:\n\n```\nnpm test -- 'playground'\n```\n\n## Informação útil\n\n### Referências\n\n- [▶ Estruturas de Dados e Algoritmos no YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [✍🏻 Esboços de Estruturas de Dados](https://okso.app/showcase/data-structures)\n\n### Notação Big O\n\nA 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.\n\n![Notação Big-O](./assets/big-o-graph.png)\n\nFonte: [Notação Big-O Dicas](http://bigocheatsheet.com/).\n\nAbaixo 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.\n\n| Notação Big-O  | Cálculos para 10 elementos   | Cálculos para 100 elementos   | Cálculos para 1000 elementos    |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### Complexidade de operações de estrutura de dados\n\n| Estrutura de dados      | Acesso    | Busca     | Inserção  | Eliminação | Comentários |\n| ----------------------- | :-------: | :-------: | :-------: | :-------:  | :--------   |\n| **Array**               | 1         | n         | n         | n          |             |\n| **Stack**               | n         | n         | 1         | 1          |             |\n| **Queue**               | n         | n         | 1         | 1          |             |\n| **Linked List**         | n         | n         | 1         | 1          |             |\n| **Hash Table**          | -         | n         | n         | n          | Em caso de uma função hash perfeita, os custos seriam O(1) |\n| **Binary Search Tree**  | n         | n         | n         | n          | No caso de custos de árvore equilibrados seria O(log(n))\n| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)     |             |\n| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)     |             |\n| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)     |             |\n| **Bloom Filter**        | -         | 1         | 1         | -          | Falsos positivos são possíveis durante a pesquisa |\n\n### Complexidade dos Algoritmos de Ordenação de Matrizes\n\n| Nome                  | Melhor          | Média               | Pior                | Mémoria   | Estável   | Comentários |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :--------   |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |             |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |             |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Não       |             |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Não       |             |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Sim       |             |\n| **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)) |\n| **Shell sort**        | n&nbsp;log(n)   | depende da sequência de lacunas | n&nbsp;(log(n))<sup>2</sup>     | 1      | Não    |                   |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Sim       | r - maior número na matriz          |\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Sim       | k - comprimento da chave mais longa |\n\n> ℹ️ Outros [projetos](https://trekhleb.dev/projects/) e [artigos](https://trekhleb.dev/blog/) sobre JavaScript e algoritmos em [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.ru-RU.md",
    "content": "# Алгоритмы и структуры данных на JavaScript\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nВ этом репозитории содержатся базовые JavaScript-примеры многих популярных алгоритмов и структур данных.\n\nДля каждого алгоритма и структуры данных есть свой файл README с соответствующими пояснениями и ссылками на материалы для дальнейшего изучения (в том числе и ссылки на видеоролики в YouTube).\n\n_Читать на других языках:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Структуры данных\n\nСтруктура данных (англ. data structure) — программная единица, позволяющая хранить и обрабатывать множество однотипных и/или логически связанных данных в вычислительной технике. Для добавления, поиска, изменения и удаления данных структура данных предоставляет некоторый набор функций, составляющих её интерфейс.\n\n`B` - Базовый уровень, `A` - Продвинутый уровень\n\n* `B` [Связный список](src/data-structures/linked-list)\n* `B` [Двунаправленный связный список](src/data-structures/doubly-linked-list)\n* `B` [Очередь](src/data-structures/queue)\n* `B` [Стек](src/data-structures/stack)\n* `B` [Хеш-таблица](src/data-structures/hash-table)\n* `B` [Куча](src/data-structures/heap) — максимальная и минимальная версии\n* `B` [Очередь с приоритетом](src/data-structures/priority-queue)\n* `A` [Префиксное дерево](src/data-structures/trie)\n* `A` [Деревья](src/data-structures/tree)\n  * `A` [Двоичное дерево поиска](src/data-structures/tree/binary-search-tree)\n  * `A` [АВЛ-дерево](src/data-structures/tree/avl-tree)\n  * `A` [Красно-чёрное дерево](src/data-structures/tree/red-black-tree)\n  * `A` [Дерево отрезков](src/data-structures/tree/segment-tree) — для минимума, максимума и суммы отрезков\n  * `A` [Дерево Фенвика](src/data-structures/tree/fenwick-tree) (двоичное индексированное дерево)\n* `A` [Граф](src/data-structures/graph) (ориентированный и неориентированный)\n* `A` [Система непересекающихся множеств](src/data-structures/disjoint-set)\n* `A` [Фильтр Блума](src/data-structures/bloom-filter)\n\n## Алгоритмы\n\nАлгоритм — конечная совокупность точно заданных правил решения некоторого класса задач или набор инструкций, описывающих порядок действий исполнителя для решения некоторой задачи.\n\n`B` - Базовый уровень, `A` - Продвинутый уровень\n\n### Алгоритмы по тематике\n\n* **Математика**\n  * `B` [Битовые манипуляции](src/algorithms/math/bits) — получение/запись/сброс/обновление битов, умножение/деление на 2, сделать отрицательным и т.п.\n  * `B` [Двоичное число с плавающей запятой](src/algorithms/math/binary-floating-point) - двоичное представление чисел с плавающей запятой\n  * `B` [Факториал](src/algorithms/math/factorial)\n  * `B` [Числа Фибоначчи](src/algorithms/math/fibonacci) — классическое решение, решение в замкнутой форме\n  * `B` [Простые множители](src/algorithms/math/prime-factors) - нахождение простых множителей и их подсчёт с использованием теоремы Харди-Рамануджана\n  * `B` [Тест простоты](src/algorithms/math/primality-test) (метод пробного деления)\n  * `B` [Алгоритм Евклида](src/algorithms/math/euclidean-algorithm) — нахождение наибольшего общего делителя (НОД)\n  * `B` [Наименьшее общее кратное](src/algorithms/math/least-common-multiple) (НОК)\n  * `B` [Решето Эратосфена](src/algorithms/math/sieve-of-eratosthenes) — нахождение всех простых чисел до некоторого целого числа n\n  * `B` [Степень двойки](src/algorithms/math/is-power-of-two) — является ли число степенью двойки (простое и побитовое решения)\n  * `B` [Треугольник Паскаля](src/algorithms/math/pascal-triangle)\n  * `B` [Комплексные числа](src/algorithms/math/complex-number) — комплексные числа, базовые операции над ними\n  * `B` [Радианы и градусы](src/algorithms/math/radian) — конвертирование радианов в градусы и наоборот\n  * `B` [Быстрое возведение в степень](src/algorithms/math/fast-powering)\n  * `B` [Схема Горнера](src/algorithms/math/horner-method) - оценка полиномов\n  * `B` [Матрицы](src/algorithms/math/matrix) - матрицы и основные операции с матрицами (умножение, транспонирование и т.д.)\n  * `B` [Евклидово расстояние](src/algorithms/math/euclidean-distance) - расстояние между двумя точками/векторами/матрицами\n  * `A` [Разбиение числа](src/algorithms/math/integer-partition)\n  * `A` [Квадратный корень](src/algorithms/math/square-root) — метод Ньютона\n  * `A` [Алгоритм Лю Хуэя](src/algorithms/math/liu-hui) — расчёт числа π с заданной точностью методом вписанных правильных многоугольников\n  * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие\n* **Множества**\n  * `B` [Декартово произведение](src/algorithms/sets/cartesian-product) — результат перемножения множеств\n  * `B` [Тасование Фишера — Йетса](src/algorithms/sets/fisher-yates) — создание случайных перестановок конечного множества\n  * `A` [Булеан](src/algorithms/sets/power-set) — все подмножества заданного множества (побитовый поиск и поиск с возвратом)\n  * `A` [Перестановки](src/algorithms/sets/permutations) (с повторениями и без повторений)\n  * `A` [Сочетания](src/algorithms/sets/combinations) (с повторениями и без повторений)\n  * `A` [Наибольшая общая подпоследовательность](src/algorithms/sets/longest-common-subsequence)\n  * `A` [Наибольшая увеличивающаяся подпоследовательность](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Наименьшая общая супер-последовательность](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Задача о рюкзаке](src/algorithms/sets/knapsack-problem) — \"0/1\" и \"неограниченный\" рюкзаки\n  * `A` [Максимальный под-массив](src/algorithms/sets/maximum-subarray) — метод полного перебора и алгоритм Кадане\n  * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу\n* **Алгоритмы работы со строками**\n  * `B` [Расстояние Хэмминга](src/algorithms/string/hamming-distance) — число позиций, в которых соответствующие символы различны\n  * `A` [Расстояние Левенштейна](src/algorithms/string/levenshtein-distance) — метрика, измеряющая разность между двумя последовательностями\n  * `A` [Алгоритм Кнута — Морриса — Пратта](src/algorithms/string/knuth-morris-pratt) — поиск подстроки (сопоставление с шаблоном)\n  * `A` [Z-функция](src/algorithms/string/z-algorithm) — поиск подстроки (сопоставление с шаблоном)\n  * `A` [Алгоритм Рабина — Карпа](src/algorithms/string/rabin-karp) — поиск подстроки\n  * `A` [Наибольшая общая подстрока](src/algorithms/string/longest-common-substring)\n  * `A` [Разборщик регулярных выражений](src/algorithms/string/regular-expression-matching)\n* **Алгоритмы поиска**\n  * `B` [Линейный поиск](src/algorithms/search/linear-search)\n  * `B` [Поиск с перескоком](src/algorithms/search/jump-search) (поиск блоков) — поиск в упорядоченном массиве\n  * `B` [Двоичный поиск](src/algorithms/search/binary-search) — поиск в упорядоченном массиве\n  * `B` [Интерполяционный поиск](src/algorithms/search/interpolation-search) — поиск в равномерно распределённом упорядоченном массиве.\n* **Алгоритмы сортировки**\n  * `B` [Сортировка пузырьком](src/algorithms/sorting/bubble-sort)\n  * `B` [Сортировка выбором](src/algorithms/sorting/selection-sort)\n  * `B` [Сортировка вставками](src/algorithms/sorting/insertion-sort)\n  * `B` [Пирамидальная сортировка (сортировка кучей)](src/algorithms/sorting/heap-sort)\n  * `B` [Сортировка слиянием](src/algorithms/sorting/merge-sort)\n  * `B` [Быстрая сортировка](src/algorithms/sorting/quick-sort) — с использованием дополнительной памяти и без её использования\n  * `B` [Сортировка Шелла](src/algorithms/sorting/shell-sort)\n  * `B` [Сортировка подсчётом](src/algorithms/sorting/counting-sort)\n  * `B` [Поразрядная сортировка](src/algorithms/sorting/radix-sort)\n* **Связный список**\n  * `B` [Прямой обход](src/algorithms/linked-list/traversal)\n  * `B` [Обратный обход](src/algorithms/linked-list/reverse-traversal)\n* **Деревья**\n  * `B` [Поиск в глубину](src/algorithms/tree/depth-first-search)\n  * `B` [Поиск в ширину](src/algorithms/tree/breadth-first-search)\n* **Графы**\n  * `B` [Поиск в глубину](src/algorithms/graph/depth-first-search)\n  * `B` [Поиск в ширину](src/algorithms/graph/breadth-first-search)\n  * `B` [Алгоритм Краскала](src/algorithms/graph/kruskal) — нахождение минимального остовного дерева для взвешенного неориентированного графа\n  * `A` [Алгоритм Дейкстры](src/algorithms/graph/dijkstra) — нахождение кратчайших путей от одной из вершин графа до всех остальных\n  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) — нахождение кратчайших путей от одной из вершин графа до всех остальных\n  * `A` [Алгоритм Флойда — Уоршелла](src/algorithms/graph/floyd-warshall) — нахождение кратчайших расстояний между всеми вершинами графа\n  * `A` [Задача нахождения цикла](src/algorithms/graph/detect-cycle) — для ориентированных и неориентированных графов (на основе поиска в глубину и системы непересекающихся множеств)\n  * `A` [Алгоритм Прима](src/algorithms/graph/prim) — нахождение минимального остовного дерева для взвешенного неориентированного графа\n  * `A` [Топологическая сортировка](src/algorithms/graph/topological-sorting) — на основе поиска в глубину\n  * `A` [Шарниры (разделяющие вершины)](src/algorithms/graph/articulation-points) — алгоритм Тарьяна (на основе поиска в глубину)\n  * `A` [Мосты](src/algorithms/graph/bridges) — на основе поиска в глубину\n  * `A` [Эйлеров путь и Эйлеров цикл](src/algorithms/graph/eulerian-path) — алгоритм Флёри (однократное посещение каждой вершины)\n  * `A` [Гамильтонов цикл](src/algorithms/graph/hamiltonian-cycle) — проходит через каждую вершину графа ровно один раз\n  * `A` [Компоненты сильной связности](src/algorithms/graph/strongly-connected-components) — алгоритм Косарайю\n  * `A` [Задача коммивояжёра](src/algorithms/graph/travelling-salesman) — кратчайший маршрут, проходящий через указанные города с последующим возвратом в исходный город\n* **Криптография**\n  * `B` [Полиноминальный хэш](src/algorithms/cryptography/polynomial-hash) — функция кольцевого хэша, основанная на полиноме\n  * `B` [Шифр ​​ограждения рельсов](src/algorithms/cryptography/rail-fence-cipher) - алгоритм транспозиционного шифра для кодирования сообщений\n  * `B` [Шифр Цезаря](src/algorithms/cryptography/caesar-cipher) - простой подстановочный шифр\n  * `B` [Шифр Хилла](src/algorithms/cryptography/hill-cipher) - подстановочный шифр на основе линейной алгебры\n* **Машинное обучение**\n  * `B` [Нано-нейрон](https://github.com/trekhleb/nano-neuron) — 7 простых JavaScript функций, отображающих способности машины к обучению (прямое и обратное распространение)\n  * `B` [k-NN](src/algorithms/ml/knn) - алгоритм классификации k-ближайших соседей\n  * `B` [k-Means](src/algorithms/ml/k-means) - алгоритм кластеризации по методу k-средних\n* **Обработка изображений**\n  * `B` [Резьба по шву](src/algorithms/image-processing/seam-carving) - алгоритм изменения размера изображения с учетом содержания\n* **Статистика**\n  * `B` [Взвешенная случайность](src/algorithms/statistics/weighted-random) - выбор случайного элемента из списка на основе веса элементов\n* **Эволюционные алгоритмы**\n  * `A` [Генетический алгоритм](https://github.com/trekhleb/self-parking-car-evolution) - пример применения генетического алгоритма для обучения самопаркующихся автомобилей\n* **Прочие алгоритмы**\n  * `B` [Ханойская башня](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Поворот квадратной матрицы](src/algorithms/uncategorized/square-matrix-rotation) — используется дополнительная память\n  * `B` [Прыжки](src/algorithms/uncategorized/jump-game) — на основе бэктрекинга, динамического программирования (сверху-вниз + снизу-вверх) и жадных алгоритмов\n  * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths) — на основе бэктрекинга, динамического программирования и треугольника Паскаля\n  * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces) — на основе перебора и динамического программирования\n  * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы (4 способа)\n  * `B` [Лучшее время для покупки и продажи акций](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - примеры \"разделяй и властвуй\" и в один проход\n  * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens)\n  * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour)\n\n### Алгоритмы по парадигме программирования\n\nПарадигма программирования — общий метод или подход, лежащий в основе целого класса алгоритмов. Понятие \"парадигма программирования\" является более абстрактным по отношению к понятию \"алгоритм\", которое в свою очередь является более абстрактным по отношению к понятию \"компьютерная программа\".\n\n* **Алгоритмы полного перебора** — поиск лучшего решения исчерпыванием всевозможных вариантов\n  * `B` [Линейный поиск](src/algorithms/search/linear-search)\n  * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces)\n  * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы\n  * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray)\n  * `A` [Задача коммивояжёра](src/algorithms/graph/travelling-salesman) — кратчайший маршрут, проходящий через указанные города с последующим возвратом в исходный город\n  * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие\n* **Жадные алгоритмы** — принятие локально оптимальных решений с учётом допущения об оптимальности конечного решения\n  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)\n  * `A` [Задача о неограниченном рюкзаке](src/algorithms/sets/knapsack-problem)\n  * `A` [Алгоритм Дейкстры](src/algorithms/graph/dijkstra) — нахождение кратчайших путей от одной из вершин графа до всех остальных\n  * `A` [Алгоритм Прима](src/algorithms/graph/prim) — нахождение минимального остовного дерева для взвешенного неориентированного графа\n  * `A` [Алгоритм Краскала](src/algorithms/graph/kruskal) — нахождение минимального остовного дерева для взвешенного неориентированного графа\n* **Разделяй и властвуй** — рекурсивное разбиение решаемой задачи на более мелкие\n  * `B` [Двоичный поиск](src/algorithms/search/binary-search)\n  * `B` [Ханойская башня](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Треугольник Паскаля](src/algorithms/math/pascal-triangle)\n  * `B` [Алгоритм Евклида](src/algorithms/math/euclidean-algorithm) — нахождение наибольшего общего делителя (НОД)\n  * `B` [Сортировка слиянием](src/algorithms/sorting/merge-sort)\n  * `B` [Быстрая сортировка](src/algorithms/sorting/quick-sort)\n  * `B` [Поиск в глубину (дерево)](src/algorithms/tree/depth-first-search)\n  * `B` [Поиск в глубину (граф)](src/algorithms/graph/depth-first-search)\n  * `B` [Матрицы](src/algorithms/math/matrix) - генерирование и обход матриц различной формы\n  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)\n  * `B` [Быстрое возведение в степень](src/algorithms/math/fast-powering)\n  * `B` [Лучшее время для покупки и продажи акций](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - примеры \"разделяй и властвуй\" и в один проход\n  * `A` [Перестановки](src/algorithms/sets/permutations) (с повторениями и без повторений)\n  * `A` [Сочетания](src/algorithms/sets/combinations) (с повторениями и без повторений)\n* **Динамическое программирование** — решение общей задачи конструируется на основе ранее найденных решений подзадач\n  * `B` [Числа Фибоначчи](src/algorithms/math/fibonacci)\n  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)\n  * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths)\n  * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces)\n  * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы\n  * `B` [Резьба по шву](src/algorithms/image-processing/seam-carving) - алгоритм изменения размера изображения с учетом содержания\n  * `A` [Расстояние Левенштейна](src/algorithms/string/levenshtein-distance) — метрика, измеряющая разность между двумя последовательностями\n  * `A` [Наибольшая общая подпоследовательность](src/algorithms/sets/longest-common-subsequence)\n  * `A` [Наибольшая общая подстрока](src/algorithms/string/longest-common-substring)\n  * `A` [Наибольшая увеличивающаяся подпоследовательность](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Наименьшая общая суперпоследовательность](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Рюкзак 0-1](src/algorithms/sets/knapsack-problem)\n  * `A` [Разбиение числа](src/algorithms/math/integer-partition)\n  * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray)\n  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) — поиск кратчайшего пути во взвешенном графе\n  * `A` [Алгоритм Флойда — Уоршелла](src/algorithms/graph/floyd-warshall) — нахождение кратчайших путей от одной из вершин графа до всех остальных\n  * `A` [Разборщик регулярных выражений](src/algorithms/string/regular-expression-matching)\n* **Поиск с возвратом (бэктрекинг)** — при поиске решения многократно делается попытка расширить текущее частичное решение. Если расширение невозможно, то происходит возврат к предыдущему более короткому частичному решению, и делается попытка его расширить другим возможным способом. Обычно используется обход пространства состояний в глубину.\n  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)\n  * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths)\n  * `B` [Булеан](src/algorithms/sets/power-set) — все подмножества заданного множества\n  * `A` [Гамильтонов цикл](src/algorithms/graph/hamiltonian-cycle) — проходит через каждую вершину графа ровно один раз\n  * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens)\n  * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour)\n  * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу\n* **Метод ветвей и границ** — основан на упорядоченном переборе решений и рассмотрении только тех из них, которые являются перспективными (по тем или иным признакам) и отбрасывании бесперспективных множеств решений. Обычно используется обход в ширину в совокупности с обходом дерева пространства состояний в глубину.\n\n## Как использовать этот репозиторий\n\n**Установка всех зависимостей**\n```\nnpm install\n```\n\n**Запуск ESLint**\n\nЭта команда может потребоваться вам для проверки качества кода.\n\n```\nnpm run lint\n```\n\n**Запуск всех тестов**\n\n```\nnpm test\n```\n\n**Запуск определённого теста**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**Песочница**\n\nВы можете экспериментировать с алгоритмами и структурами данных в файле `./src/playground/playground.js`\n(файл `./src/playground/__test__/playground.test.js` предназначен для написания тестов).\n\nДля проверки работоспособности вашего кода используйте команду:\n\n```\nnpm test -- 'playground'\n```\n\n## Полезная информация\n\n### Ссылки\n\n[▶ О структурах данных и алгоритмах](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Нотация «О» большое\n\n*Нотация «О» большое* используется для классификации алгоритмов в соответствии с ростом времени выполнения и затрачиваемой памяти при увеличении размера входных данных. На диаграмме ниже представлены общие порядки роста алгоритмов в соответствии с нотацией «О» большое.\n\n![Big O graphs](./assets/big-o-graph.png)\n\nИсточник: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nНиже представлены часто используемые обозначения в нотации «О» большое, а также сравнение их производительностей на различных размерах входных данных.\n\n| Нотация «О» большое | 10 элементов | 100 элементов | 1000 элементов |\n| ------------------- | ------------ | ------------- | -------------- |\n| **O(1)**            | 1            | 1             | 1              |\n| **O(log N)**        | 3            | 6             | 9              |\n| **O(N)**            | 10           | 100           | 1000           |\n| **O(N log N)**      | 30           | 600           | 9000           |\n| **O(N^2)**          | 100          | 10000         | 1000000        |\n| **O(2^N)**          | 1024         | 1.26e+29      | 1.07e+301      |\n| **O(N!)**           | 3628800      | 9.3e+157      | 4.02e+2567     |\n\n### Сложности операций в структурах данных\n\n| Структура данных           | Получение | Поиск     | Вставка   | Удаление  | Комментарии |\n| -------------------------- | :-------: | :-------: | :-------: | :-------: | :---------- |\n| **Массив**                 | 1         | n         | n         | n         |             |\n| **Стек**                   | n         | n         | 1         | 1         |             |\n| **Очередь**                | n         | n         | 1         | 1         |             |\n| **Связный список**         | n         | n         | 1         | n         |             |\n| **Хеш-таблица**            | -         | n         | n         | n         | Для идеальной хеш-функции — O(1) |\n| **Двоичное дерево поиска** | n         | n         | n         | n         | В сбалансированном дереве — O(log(n)) |\n| **B-дерево**               | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Красно-чёрное дерево**   | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **АВЛ-дерево**             | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Фильтр Блума**           | -         | 1         | 1         | -         | Возможно получение ложно-положительного срабатывания |\n\n### Сложности алгоритмов сортировки\n\n| Наименование               | Лучший случай | Средний случай | Худший случай | Память | Устойчивость | Комментарии |\n| -------------------------- | :-----------: | :------------: | :-----------: | :----: | :----------: | :---------- |\n| **Сортировка пузырьком**   | n             | n<sup>2</sup>  | n<sup>2</sup> | 1      | Да           |             |\n| **Сортировка вставками**   | n             | n<sup>2</sup>  | n<sup>2</sup> | 1      | Да           |             |\n| **Сортировка выбором**     | n<sup>2</sup> | n<sup>2</sup>  | n<sup>2</sup> | 1      | Нет          |             |\n| **Сортировка кучей**       | n&nbsp;log(n) | n&nbsp;log(n)  | n&nbsp;log(n) | 1      | Нет          |             |\n| **Сортировка слиянием**    | n&nbsp;log(n) | n&nbsp;log(n)  | n&nbsp;log(n) | n      | Да           |             |\n| **Быстрая сортировка**     | n&nbsp;log(n) | n&nbsp;log(n)  | n<sup>2</sup> | log(n) | Нет          | Быстрая сортировка обычно выполняется с использованием O(log(n)) дополнительной памяти |\n| **Сортировка Шелла**       | n&nbsp;log(n) | зависит от выбранных шагов | n&nbsp;(log(n))<sup>2</sup>  | 1      | Нет          |           |\n| **Сортировка подсчётом**   | n + r         | n + r          | n + r         | n + r  | Да           | r — наибольшее число в массиве |\n| **Поразрядная сортировка** | n * k         | n * k          | n * k         | n + k  | Да           | k — длина самого длинного ключа |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.tr-TR.md",
    "content": "# JavaScript Algoritmalar ve Veri Yapıları\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nBu repository popüler algoritmaların ve veri yapılarının birçoğunun Javascript tabanlı örneklerini bulundurur.\n\nHer bir algoritma ve veri yapısı kendine\nait açıklama ve videoya sahip README dosyası içerir.\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Veri Yapıları\n\nBir veri yapısı, verileri bir bilgisayarda organize etmenin ve depolamanın belirli bir yoludur, böylece\nverimli bir şekilde erişilebilir ve değiştirilebilir. Daha iyi ifadeyle, bir veri yapısı bir veri koleksiyonudur,\naralarındaki ilişkiler, ve işlevler veya işlemler\nveriye uygulanabilir.\n\n`B` - Başlangıç, `A` - İleri Seviye\n\n* `B` [Bağlantılı Veri Yapısı](src/data-structures/linked-list)\n* `B` [Çift Yönlü Bağlı Liste](src/data-structures/doubly-linked-list)\n* `B` [Kuyruk](src/data-structures/queue)\n* `B` [Yığın](src/data-structures/stack)\n* `B` [Hash Table](src/data-structures/hash-table)\n* `B` [Heap](src/data-structures/heap) - max and min heap versions\n* `B` [Öncelikli Kuyruk](src/data-structures/priority-queue)\n* `A` [Trie](src/data-structures/trie)\n* `A` [Ağaç](src/data-structures/tree)\n  * `A` [İkili Arama Ağaçları](src/data-structures/tree/binary-search-tree)\n  * `A` [AVL Tree](src/data-structures/tree/avl-tree)\n  * `A` [Red-Black Tree](src/data-structures/tree/red-black-tree)\n  * `A` [Segment Tree](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples\n  * `A` [Fenwick Tree](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)\n* `A` [Graph](src/data-structures/graph) (both directed and undirected)\n* `A` [Disjoint Set](src/data-structures/disjoint-set)\n* `A` [Bloom Filter](src/data-structures/bloom-filter)\n\n## Algoritmalar\n\nBir algoritma, bir problem sınıfının nasıl çözüleceğine dair kesin bir tanımlamadır.\nBir işlem dizisini açık olarak tanımlayan kurallar dizisidir.\n\n\n`B` - Başlangıç, `A` - İleri Seviye\n\n### Konusuna göre Algoritma\n\n* **Matematik**\n  * `B` [Bit Manipülasyonu](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc.\n  * `B` [İkili Kayan Nokta](src/algorithms/math/binary-floating-point) - kayan noktalı sayıların ikilik sistemde gösterimi.\n  * `B` [Faktöriyel](src/algorithms/math/factorial)\n  * `B` [Fibonacci Sayısı](src/algorithms/math/fibonacci) - klasik ve kapalı-form versiyonları\n  * `B` [Asallık Testi](src/algorithms/math/primality-test) (deneyerek bölüm metodu)\n  * `B` [Öklid Algoritması](src/algorithms/math/euclidean-algorithm) - En büyük ortak bölen hesaplama (EBOB)\n  * `B` [En küçük Ortak Kat](src/algorithms/math/least-common-multiple) (EKOK)\n  * `B` [Eratosten Kalburu](src/algorithms/math/sieve-of-eratosthenes) - belirli bir sayıya kadarki asal sayıları bulma\n  * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - sayı ikinin katı mı sorgusu (naive ve bitwise algoritmaları)\n  * `B` [Paskal Üçgeni](src/algorithms/math/pascal-triangle)\n  * `B` [Karmaşık Sayılar](src/algorithms/math/complex-number) - karmaşık sayılar ve karmaşık sayılar ile temel işlemler\n  * `B` [Radyan & Derece](src/algorithms/math/radian) - radyandan dereceye çeviri ve tersine çeviri\n  * `B` [Fast Powering](src/algorithms/math/fast-powering)\n  * `B` [Horner's method](src/algorithms/math/horner-method) - polinomal ifadelerin değerlendirilmesi\n  * `B` [Matrices](src/algorithms/math/matrix) - matrisler ve basit matris operasyonları (çarpım, tersçapraz, vb.)\n  * `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - iki nokta/vektör/matris arasındaki mesafe\n  * `A` [Tamsayı Bölümü](src/algorithms/math/integer-partition)\n  * `A` [Karekök](src/algorithms/math/square-root) - Newton yöntemi\n  * `A` [Liu Hui π Algoritması](src/algorithms/math/liu-hui) - N-gons'a göre yaklaşık π hesabı\n  * `A` [Ayrık Fourier Dönüşümü](src/algorithms/math/fourier-transform) - bir zaman fonksiyonunu (sinyal) içerdiği frekanslara ayırın\n* **Setler**\n  * `B` [Kartezyen Ürün](src/algorithms/sets/cartesian-product) - birden fazla kümenin çarpımı\n  * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - sonlu bir dizinin rastgele permütasyonu\n  * `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bit düzeyinde ve geri izleme yöntemleri)\n  * `A` [Permütasyonlar](src/algorithms/sets/permutations)(tekrarlı ve tekrarsız)\n  * `A` [Kombinasyonlar](src/algorithms/sets/combinations) (tekrarlı ve tekrarsız)\n  * `A` [En Uzun Ortak Altdizi](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [En Uzun Artan Altdizi](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [En Kısa Ortak Üst Sıra](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Knapsack Problem](src/algorithms/sets/knapsack-problem) - \"0-1 sırt çantası problemi\" ve \"Sınırsız sırt çantası problemi\"\n  * `A` [Maksimum Altdizi](src/algorithms/sets/maximum-subarray) - \"Kaba Kuvvet\" ve \"Dinamik Programlara\" (Kadane'nin) versiyonu\n  * `A` [Kombinasyon Toplamı](src/algorithms/sets/combination-sum) - belirli toplamı oluşturan tüm kombinasyonları bulun\n* **Metin**\n  * `B` [Hamming Mesafesi](src/algorithms/string/hamming-distance) - sembollerin farklı olduğu konumların sayısı\n  * `A` [Levenshtein Mesafesi](src/algorithms/string/levenshtein-distance) - iki sekans arasındaki minimum düzenleme mesafesi\n  * `A` [Knuth–Morris–Pratt Algoritması](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - altmetin araması (örüntü eşleme)\n  * `A` [Z Algoritması](src/algorithms/string/z-algorithm) - altmetin araması (desen eşleştirme)\n  * `A` [Rabin Karp Algoritması](src/algorithms/string/rabin-karp) - altmetin araması\n  * `A` [En Uzun Ortak Alt Metin](src/algorithms/string/longest-common-substring)\n  * `A` [Regular Expression Eşleme](src/algorithms/string/regular-expression-matching)\n* **Aramalar**\n  * `B` [Doğrusal Arama](src/algorithms/search/linear-search)\n  * `B` [Jump Search](src/algorithms/search/jump-search) (ya da Block Search) - sıralı dizide arama\n  * `B` [İkili Arama](src/algorithms/search/binary-search) - sıralı dizide arama\n  * `B` [Interpolation Search](src/algorithms/search/interpolation-search) - tekdüze dağıtılmış sıralı dizide arama\n* **Sıralama**\n  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)\n  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)\n  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)\n  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations\n  * `B` [Shellsort](src/algorithms/sorting/shell-sort)\n  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)\n  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)\n* **Bağlantılı Liste**\n  * `B` [Straight Traversal](src/algorithms/linked-list/traversal)\n  * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)\n* **Ağaçlar**\n  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)\n* **Graphs**\n  * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma\n  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - tek tepe noktasından tüm grafik köşelerine en kısa yolları bulmak\n  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - tek tepe noktasından tüm grafik köşelerine en kısa yolları bulmak\n  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - tüm köşe çiftleri arasındaki en kısa yolları bulun\n  * `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)\n  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma\n  * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS metodu\n  * `A` [Articulation Points](src/algorithms/graph/articulation-points) - Tarjan's algoritması (DFS based)\n  * `A` [Bridges](src/algorithms/graph/bridges) - DFS yöntemi ile algoritma\n  * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - Fleury'nin algoritması - Her kenara tam olarak bir kez ulaş\n  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Her köşeyi tam olarak bir kez ziyaret et\n  * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm\n  * `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\n* **Kriptografi**\n  * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - polinom temelinde dönen hash işlevi\n  * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher\n* **Makine Öğrenmesi**\n  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation)\n* **Kategoriye Ayrılmayanlar**\n  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - tepeye ulaşmanın yollarını sayma (4 çözüm)\n  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n\n### Algoritmik Paradigma\n\nAlgoritmik paradigma, bir sınıfın tasarımının altında yatan genel bir yöntem veya yaklaşımdır.\nAlgoritma dizayn tekniği olarak düşünülebilir. Her bir altproblemi (subproblem) asıl problemle\nbenzerlik gösteren problemlere uygulanabilir.\n\n* **Brute Force** - mümkün olan tüm çözümleri tara ve en iyisini seç\n  * `B` [Doğrusal Arama](src/algorithms/search/linear-search)\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - tepeye çıkmanın yollarını hesapla\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)\n  * `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\n  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - bir zaman fonksiyonunu (bir sinyal) onu oluşturan frekanslara ayırır\n* **Açgözlü** - geleceği düşünmeden şu an için en iyi seçeneği seçin\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem)\n  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - tüm grafik köşelerine giden en kısa yolu bulmak\n  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma\n  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma\n* **Böl ve Fethet** - sorunu daha küçük parçalara bölün ve sonra bu parçaları çözün\n  * `B` [Binary Search](src/algorithms/search/binary-search)\n  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)\n  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)\n  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)\n  * `B` [Quicksort](src/algorithms/sorting/quick-sort)\n  * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Fast Powering](src/algorithms/math/fast-powering)\n  * `A` [Permutations](src/algorithms/sets/permutations) (tekrarlı ve tekrarsız)\n  * `A` [Combinations](src/algorithms/sets/combinations) (tekrarlı ve tekrarsız)\n* **Dinamik Programlama** - önceden bulunan alt çözümleri kullanarak bir çözüm oluşturmak\n  * `B` [Fibonacci Sayısı](src/algorithms/math/fibonacci)\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Eşsiz Yol](src/algorithms/uncategorized/unique-paths)\n  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem\n  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - zirveye ulaşmanın yollarının sayısını sayın\n  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - iki sekans arasındaki minimum düzenleme mesafesi\n  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)\n  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem)\n  * `A` [Integer Partition](src/algorithms/math/integer-partition)\n  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)\n  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - tüm grafik köşelerine giden en kısa yolu bulmak\n  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - tüm köşe çiftleri arasındaki en kısa yolları bulun\n  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)\n* **Backtracking** - brute forceye benzer, mümkün tüm sonuçları tara, ancak bir sonraki çözümü her ürettiğinizde test edersiniz\ntü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(?).\nNormally the DFS traversal of state-space is being used.\n  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)\n  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)\n  * `B` [Power Set](src/algorithms/sets/power-set) - all subsets of a set\n  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Her köşeyi tam olarak bir kez ziyaret edin\n  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)\n  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)\n  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - belirli toplamı oluşturan tüm kombinasyonları bulun\n* **Branch & Bound** - remember the lowest-cost solution found at each stage of the backtracking\nsearch, and use the cost of the lowest-cost solution found so far as a lower bound on the cost of\na least-cost solution to the problem, in order to discard partial solutions with costs larger than the\nlowest-cost solution found so far. Normally BFS traversal in combination with DFS traversal of state-space\ntree is being used.\n\n## Repository'in Kullanımı\n\n**Bütün dependencyleri kurun**\n```\nnpm install\n```\n\n**ESLint'i başlatın**\n\nBunu kodun kalitesini kontrol etmek amacı ile çalıştırabilirsin.\n\n```\nnpm run lint\n```\n\n**Bütün testleri çalıştır**\n```\nnpm test\n```\n\n**Testleri ismine göre çalıştır**\n```\nnpm test -- 'LinkedList'\n```\n\n**Deneme Alanı**\n\ndata-structures ve algorithms içerisinde `./src/playground/playground.js`\nyazarak `./src/playground/__test__/playground.test.js` için test edebilirsin.\n\n\nArdından basitçe alttaki komutu girerek kodunun beklendiği gibi çalışıp çalışmadığını test edebilirsin:\n\n```\nnpm test -- 'playground'\n```\n\n## Yararlı Bilgiler\n\n### Referanslar\n\n[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Big O Notation\n\n* 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.\nAşağıdaki grafikte, Big O gösteriminde belirtilen algoritmaların en yaygın büyüme sıralarını bulabilirsiniz.\n\n![Big O graphs](./assets/big-o-graph.png)\n\nKaynak: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nAltta Big O notations ve farklı input boyutlarına karşın yapılmış performans karşılaştırması listelenmektedir.\n\n| Big O Notation | 10 Element için hesaplama | 100 Element için hesaplama | 1000 Element için hesaplama  |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### Veri Yapısı İşlem Karmaşıklığı\n\n| Veri Yapısı          | Access    | Search    | Insertion | Deletion  | Comments  |\n| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |\n| **Dizi**               | 1         | n         | n         | n         |           |\n| **Yığın**               | n         | n         | 1         | 1         |           |\n| **Sıralı**               | n         | n         | 1         | 1         |           |\n| **Bağlantılı Liste**         | n         | n         | 1         | n         |           |\n| **Yığın Tablo**          | -         | n         | n         | n         | Kusursuz hash fonksiyonu durumunda sonuç O(1) |\n| **İkili Arama Ağacı**  | n         | n         | n         | n         | In case of balanced tree costs would be O(log(n)) |\n| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Bloom Filter**        | -         | 1         | 1         | -         | Arama esnasında yanlış sonuçlar çıkabilir |\n\n### Dizi Sıralama Algoritmaları Karmaşıklığı\n\n| İsim                  | En İyi            | Ortalama             | En Kötü               | Hafıza    | Kararlı    | Yorumlar  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Evet       |           |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Evet       |           |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Hayır        |           |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Hayır        |           |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Evet       |           |\n| **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 |\n| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | Hayır         |           |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Evet       | r - dizideki en büyük sayı |\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Evet       | k - en uzun key'in uzunluğu |\n\n## Projeyi Destekleme\n\nBu projeyi buradan destekleyebilirsiniz ❤️️ [GitHub](https://github.com/sponsors/trekhleb) veya ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.uk-UA.md",
    "content": "# Алгоритми JavaScript та структури даних\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nДаний репозиторій приклади багатьох популярних алгоритмів та структур даних на основі JavaScript.\n\nКожен алгоритм та структура даних має свій окремий README-файл із відповідними поясненнями та посиланнями для подальшого вивчення (включаючи посилання на відео на YouTube).\n\n_Вивчення матеріалу на інших мовах:_\n[_English_](README.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Структури даних\n\nСтруктура даних (в програмуванні) - це спосіб організації даних в комп'ютерах. Часто разом зі структурою даних пов'язується і специфічний перелік операцій, що можуть бути виконаними над даними, організованими в таку структуру.\nТочніше, структура даних - це сукупність даних цінності, взаємозв'язки між ними та функції або операції, до яких можна застосувати дані.\n\n`B` - Початківець, `A` - Просунутий рівень\n\n* `B` [Зв'язаний список](src/data-structures/linked-list)\n* `B` [Двобічно зв'язаний список](src/data-structures/doubly-linked-list)\n* `B` [Черга](src/data-structures/queue)\n* `B` [Стек](src/data-structures/stack)\n* `B` [Геш-таблиця](src/data-structures/hash-table)\n* `B` [Купа, стіс або піраміда](src/data-structures/heap) - max and min heap versions\n* `B` [Черга з пріоритетом](src/data-structures/priority-queue)\n* `A` [Префіксне дерево](src/data-structures/trie)\n* `A` [Дерево](src/data-structures/tree)\n  * `A` [Двійкове дерево пошуку](src/data-structures/tree/binary-search-tree)\n  * `A` [АВЛ-дерево](src/data-structures/tree/avl-tree)\n  * `A` [Червоно-чорне дерево](src/data-structures/tree/red-black-tree)\n  * `A` [Дерево відрізків](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples\n  * `A` [Дерево Фенвіка](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)\n* `A` [Граф (абстрактний тип даних)](src/data-structures/graph) (both directed and undirected)\n* `A` [Система неперетинних множин](src/data-structures/disjoint-set)\n* `A` [Фільтр Блума](src/data-structures/bloom-filter)\n\n\n## Алгоритми\n\nАлгоритм - це однозначна специфікація способу вирішення класу задач. Це набір правил, які точно визначають послідовність операцій.\n\n`B` - Початківець, `A` - Просунутий рівень\n\n### Алгоритми за тематикою\n\n* **Математика**\n  * `B` [Бітова маніпуляція](src/algorithms/math/bits) - встановити / отримати / оновити / очистити біти, множення / ділення на два, робити від’ємними тощо\n  * `B` [Факторіал](src/algorithms/math/factorial)\n  * `B` [Послідовність Фібоначчі](src/algorithms/math/fibonacci) - класична та закриті версії\n  * `B` [Основні фактори](src/algorithms/math/prime-factors) - пошук простих множників і підрахунок їх за допомогою теореми Харді-Рамануджана\n  * `B` [Тест простоти](src/algorithms/math/primality-test) (метод пробного поділу)\n  * `B` [Алгоритм Евкліда](src/algorithms/math/euclidean-algorithm) - метод обчислення найбільшого спільного дільника (НСД)\n  * `B` [Найменше спільне кратне](src/algorithms/math/least-common-multiple) (НСК)\n  * `B` [Решето Ератосфена](src/algorithms/math/sieve-of-eratosthenes) - алгоритм знаходження всіх простих чисел менших деякого цілого числа *n*\n  * `B` [Піднесення до степеня](src/algorithms/math/is-power-of-two) - перевірити, чи є число ступенем двох (просте та побітове рішення)\n  * `B` [Трикутник Паскаля](src/algorithms/math/pascal-triangle)\n  * `B` [Комплексне число](src/algorithms/math/complex-number) - комплексні числа та основні операції з ними\n  * `B` [Радіани & Градуси](src/algorithms/math/radian) - перетворення радіанів у градуси та навпаки\n  * `B` [Швидке піднесення до степеня](src/algorithms/math/fast-powering)\n  * `B` [Схема Горнера](src/algorithms/math/horner-method) - поліноміальна оцінка\n  * `A` [Розбиття числа](src/algorithms/math/integer-partition)\n  * `A` [Метод дотичних (метод Ньютона)](src/algorithms/math/square-root) - метод наближеного знаходження кореня дійсного рівняння\n  * `A` [Алгоритм Лю Хуея](src/algorithms/math/liu-hui) - розрахунок числа π з заданою точністю методом вписаних правильних багатокутників\n  * `A` [Дискретне перетворення Фур'є](src/algorithms/math/fourier-transform) - розкладання тимчасової функції (сигналу) на частотні складові\n* **Множина**\n  * `B` [Декартів добуток множин](src/algorithms/sets/cartesian-product) - множина усіх можливих впорядкованих пар\n  * `B` [Тасування Фішера - Єйтса](src/algorithms/sets/fisher-yates) - створення випадкових перестановок кінцевого безлічі\n  * `A` [Булеан](src/algorithms/sets/power-set) - множина всіх підмножин даної множини (бітові та зворотні рішення)\n  * `A` [Перестановка](src/algorithms/sets/permutations) (з повтореннями та без)\n  * `A` [Комбінації](src/algorithms/sets/combinations) (з повтореннями та без)\n  * `A` [Пошук найдовшої спільної підпослідовності](src/algorithms/sets/longest-common-subsequence)\n  * `A` [Завдання пошуку найбільшою збільшується підпослідовності](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Найменша загальна супер-послідовність](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади \"0/1\" та \"Необмежений\"\n  * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray) - метод «Грубої сили» та алгоритм Кадана\n  * `A` [Комбінована сума](src/algorithms/sets/combination-sum) - знайти всі комбінації, що утворюють конкретну суму\n* **Алгоритми роботи з рядками**\n  * `B` [Відстань Геммінга](src/algorithms/string/hamming-distance) - число позицій, у яких відповідні цифри двох двійкових слів однакової довжини різні\n  * `A` [Відстань Левенштейна](src/algorithms/string/levenshtein-distance) - міра відмінності двох послідовностей символів (рядків)\n  * `A` [Алгоритм Кнута — Морріса — Пратта](src/algorithms/string/knuth-morris-pratt) пошук підрядків (узгодження шаблонів)\n  * `A` [Z-функція](src/algorithms/string/z-algorithm) - пошук підрядків (зіставлення зразків)\n  * `A` [Алгоритм Рабіна — Карпа](src/algorithms/string/rabin-karp) - алгоритм пошуку рядка\n  * `A` [Найбільший загальний підрядок](src/algorithms/string/longest-common-substring)\n  * `A` [Підбирання регулярного виразу](src/algorithms/string/regular-expression-matching)\n* **Алгоритми пошуку**\n  * `B` [Лінійний пошук](src/algorithms/search/linear-search)\n  * `B` [Пошук блоків](src/algorithms/search/jump-search) - пошук у відсортованому масиві\n  * `B` [Двійковий пошук](src/algorithms/search/binary-search) - знаходження заданого значення у впорядкованому масиві\n  * `B` [Інтерполяційний алгоритм пошуку](src/algorithms/search/interpolation-search) - алгоритм для пошуку за заданим ключем в індексованому масиві, який впорядкований за значенням ключів\n* **Алгоритми сортування**\n  * `B` [Сортування бульбашкою](src/algorithms/sorting/bubble-sort)\n  * `B` [Сортування вибором](src/algorithms/sorting/selection-sort)\n  * `B` [Сортування включенням](src/algorithms/sorting/insertion-sort)\n  * `B` [Пірамідальне сортування](src/algorithms/sorting/heap-sort)\n  * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort)\n  * `B` [Швидке сортування](src/algorithms/sorting/quick-sort)\n  * `B` [Сортування Шелла](src/algorithms/sorting/shell-sort)\n  * `B` [Сортування підрахунком](src/algorithms/sorting/counting-sort)\n  * `B` [Сортування за розрядами](src/algorithms/sorting/radix-sort)\n* **Зв’язані списки**\n  * `B` [Прямий обхід](src/algorithms/linked-list/traversal)\n  * `B` [Зворотний обхід](src/algorithms/linked-list/reverse-traversal)\n* **Дерева**\n  * `B` [Пошук у глибину](src/algorithms/tree/depth-first-search)\n  * `B` [Пошук у ширину](src/algorithms/tree/breadth-first-search)\n* **Графи**\n  * `B` [Пошук у глибину](src/algorithms/graph/depth-first-search)\n  * `B` [Пошук у ширину](src/algorithms/graph/breadth-first-search)\n  * `B` [Алгоритм Крускала](src/algorithms/graph/kruskal) - алгоритм побудови мінімального кістякового дерева зваженого неорієнтовного графа\n  * `A` [Алгоритм Дейкстри](src/algorithms/graph/dijkstra) - знаходження найкоротшого шляху від однієї вершини графа до всіх інших вершин\n  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) -  алгоритм пошуку найкоротшого шляху в зваженому графі\n  * `A` [Алгоритм Флойда — Воршелла](src/algorithms/graph/floyd-warshall) -  знаходження найкоротшого шляху в зваженому графі з додатними або від'ємними вагами ребер (але без від'ємнозначних циклів)\n  * `A` [Циклічний граф](src/algorithms/graph/detect-cycle) - граф, що складається з єдиного циклу, або, іншими словами, деякого числа вершин, з'єднаних замкнутим ланцюгом.\n  * `A` [Алгоритм Прима](src/algorithms/graph/prim) - жадібний алгоритм побудови мінімального кістякового дерева зваженого зв'язного неорієнтованого графа\n  * `A` [Топологічне сортування](src/algorithms/graph/topological-sorting) - впорядковування вершин безконтурного орієнтованого графа згідно з частковим порядком, визначеним ребрами цього графу на множині його вершин\n  * `A` [Алгоритм Тар'яна](src/algorithms/graph/articulation-points) - алгоритм пошуку компонент сильної зв'язності в орієнтованому графі, що працює за лінійний час\n  * `A` [Міст (теорія графів)](src/algorithms/graph/bridges)\n  * `A` [Ейлерів ланцюг](src/algorithms/graph/eulerian-path) - ланцюг у графі, який проходить кожне ребро рівно один раз\n  * `A` [Гамільтонів граф](src/algorithms/graph/hamiltonian-cycle) - шлях, що містить кожну вершину графа рівно один раз\n  * `A` [Компонента сильної зв'язності графа](src/algorithms/graph/strongly-connected-components) - Алгоритм Косараджу - алгоритм для знаходження компонент сильної зв’язності орієнтованого графу\n  * `A` [Задача комівояжера](src/algorithms/graph/travelling-salesman) - знаходження найвигіднішого маршруту, що проходить через вказані міста хоча б по одному разу\n* **Криптографія**\n  * `B` [Хеш-функція](src/algorithms/cryptography/polynomial-hash) - функція, що перетворює вхідні дані будь-якого (як правило великого) розміру в дані фіксованого розміру.\n  * `B` [Шифр Цезаря (шифр зсуву)](src/algorithms/cryptography/caesar-cipher) - симетричний моноалфавітний алгоритм шифрування, в якому кожна буква відкритого тексту заміняється на ту, що віддалена від неї в алфавіті на сталу кількість позицій\n  * `B` [Шифр Гілла](src/algorithms/cryptography/hill-cipher) - поліграмний шифр підстановки, заснований на лінійній алгебрі\n* **Машинне навчання**\n  * `B` [Нано-нейрон](https://github.com/trekhleb/nano-neuron) - 7 простих функцій JS, які ілюструють, як машини насправді можуть навчатися (пряме та зворотнє поширення)\n  * `B` [Метод k-найближчих сусідів](src/algorithms/ml/knn) - простий непараметричний класифікаційний метод, де для класифікації об'єктів у рамках простору властивостей використовуються відстані (зазвичай евклідові), пораховані до усіх інших об'єктів\n  * `B` [Кластеризація методом к–середніх](src/algorithms/ml/knn) - популярний метод кластеризації, — впорядкування множини об'єктів в порівняно однорідні групи.\n* **Без категорії**\n  * `B` [Ханойська вежа](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Поворот квадратної матриці](src/algorithms/uncategorized/square-matrix-rotation)\n  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади\n  * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля\n  * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - проблема захоплення дощової води (динамічне програмування та версії грубої сили)\n  * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини (4 рішення)\n  * `A` [Задача про вісім ферзів](src/algorithms/uncategorized/n-queens)\n  * `A` [Задача про хід коня](src/algorithms/uncategorized/knight-tour)\n\n### Парадигма програмування\n\nПарадиигма програмува́ння — це система ідей і понять, які визначають стиль написання комп'ютерних програм, а також спосіб мислення програміста. Це спосіб концептуалізації, що визначає організацію обчислень і структурування роботи, яку виконує комп'ютер.\n\n* **Метод «грубої сили» або повний перебір** - метод рішення криптографічної задачі шляхом перебору всіх можливих варіантів ключа\n  * `B` [Лінійний пошук](src/algorithms/search/linear-search)\n  * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - задача про дощові тераси\n  * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини\n  * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray)\n  * `A` [Задача комівояжера](src/algorithms/graph/travelling-salesman) - знаходження найвигіднішого маршруту, що проходить через вказані міста хоча б по одному разу\n  * `A` [Дискретне перетворення Фур'є](src/algorithms/math/fourier-transform) - розкладання тимчасової функції (сигналу) на частотні складові\n* **\"Жадібні\" алгоритми** - простий і прямолінійний евристичний алгоритм, який приймає найкраще рішення, виходячи з наявних на кожному етапі даних, не зважаючи на можливі наслідки, сподіваючись урешті-решт отримати оптимальний розв'язок\n  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади\n  * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади \"0/1\" та \"Необмежений\"\n  * `A` [Алгоритм Дейкстри](src/algorithms/graph/dijkstra) - знаходження найкоротшого шляху від однієї вершини графа до всіх інших вершин\n  * `A` [Алгоритм Прима](src/algorithms/graph/prim) - жадібний алгоритм побудови мінімального кістякового дерева зваженого зв'язного неорієнтованого графа\n  * `A` [Алгоритм Крускала](src/algorithms/graph/kruskal) - алгоритм побудови мінімального кістякового дерева зваженого неорієнтовного графа\n* **Розділяй і володарюй** - важлива парадигма розробки алгоритмів, що полягає в рекурсивному розбитті розв'язуваної задачі на дві або більше підзадачі того ж типу, але меншого розміру, і комбінуванні їх розв'язків для отримання відповіді до вихідного завдання. Розбиття виконуються доти, поки всі підзавдання не стануть елементарними.\n  * `B` [Двійковий пошук](src/algorithms/search/binary-search) - знаходження заданого значення у впорядкованому масиві\n  * `B` [Ханойська вежа](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Трикутник Паскаля](src/algorithms/math/pascal-triangle)\n  * `B` [Алгоритм Евкліда](src/algorithms/math/euclidean-algorithm) - метод обчислення найбільшого спільного дільника (НСД)\n  * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort)\n  * `B` [Швидке сортування](src/algorithms/sorting/quick-sort)\n  * `B` [Пошук у глибину](src/algorithms/tree/depth-first-search)\n  * `B` [Пошук у ширину](src/algorithms/tree/breadth-first-search)\n  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади\n  * `B` [Швидке піднесення до степеня](src/algorithms/math/fast-powering)\n  * `A` [Перестановка](src/algorithms/sets/permutations) (з повтореннями та без)\n  * `A` [Комбінації](src/algorithms/sets/combinations) (з повтореннями та без)\n* **Динамічне програмування** - розділ математики, який присвячено теорії і методам розв'язання багатокрокових задач оптимального управління\n  * `B` [Послідовність Фібоначчі](src/algorithms/math/fibonacci) - класична та закриті версії\n  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади\n  * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля\n  * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - проблема захоплення дощової води (динамічне програмування та версії грубої сили)\n  * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини (4 рішення)\n  * `A` [Відстань Левенштейна](src/algorithms/string/levenshtein-distance) - міра відмінності двох послідовностей символів (рядків)\n  * `A` [Пошук найдовшої спільної підпослідовності](src/algorithms/sets/longest-common-subsequence)\n  * `A` [Найбільший загальний підрядок](src/algorithms/string/longest-common-substring)\n  * `A` [Завдання пошуку найбільшою збільшується підпослідовності](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Найменша загальна супер-послідовність](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади \"0/1\" та \"Необмежений\"\n  * `A` [Розбиття числа](src/algorithms/math/integer-partition)\n  * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray)\n  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) -  алгоритм пошуку найкоротшого шляху в зваженому графі\n  * `A` [Алгоритм Флойда — Воршелла](src/algorithms/graph/floyd-warshall) -  знаходження найкоротшого шляху в зваженому графі з додатними або від'ємними вагами ребер (але без від'ємнозначних циклів)\n  * `A` [Підбирання регулярного виразу](src/algorithms/string/regular-expression-matching)\n* **Пошук із зворотом** - подібно до грубої сили, намагайтеся генерувати всі можливі рішення, але кожного разу, коли ви створюєте наступне рішення, тестуєте чи він задовольняє всім умовам, і лише потім продовжуєте генерувати наступні рішення. В іншому випадку поверніться назад і рухайтесь далі іншим шляхом пошуку рішення.\n  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади\n  * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля\n  * `B` [Булеан](src/algorithms/sets/power-set) - множина всіх підмножин даної множини (бітові та зворотні рішення)\n  * `A` [Гамільтонів граф](src/algorithms/graph/hamiltonian-cycle) - шлях, що містить кожну вершину графа рівно один раз\n  * `A` [Задача про вісім ферзів](src/algorithms/uncategorized/n-queens)\n  * `A` [Задача про хід коня](src/algorithms/uncategorized/knight-tour)\n  * `A` [Комбінована сума](src/algorithms/sets/combination-sum) - знайти всі комбінації, що утворюють конкретну суму\n* **Метод гілок і меж** - один з поширених методів дискретної оптимізації. Метод працює на дереві рішень та визначає принципи роботи конкретних алгоритмів пошуку розв'язків, тобто, є мета-алгоритмом. Для різних задач комбінаторної оптимізації створюють спеціалізовані алгоритми гілок та меж.\n\n## Як користуватися цим репозиторієм\n\n**Встановіть усі залежності**\n```\nnpm install\n```\n\n**Запустіть ESLint**\n\nЗапустіть для перевірки якості коду\n\n```\nnpm run lint\n```\n\n**Запустіть усі тести**\n```\nnpm test\n```\n\n**Запустіть тести за назвою**\n```\nnpm test -- 'LinkedList'\n```\n\n**Ігрище**\n\nВи можете побавитись зі структурами даних та алгоритмами в файлі `./src/playground/playground.js` та писати тести до них в даному файлі `./src/playground/__test__/playground.test.js`.\n\nДля перевірки, чи працює ваш код належним чином запустіть команду:\n\n```\nnpm test -- 'playground'\n```\n\n## Корисна інформація\n\n### Список літератури\n\n[▶ Структури даних та алгоритми на YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Асимптотична нотація великого О (нотація Ландау)\n\n*Асимптотична нотація великого О (нотація Ландау)* розповсюджена математична нотація для формального запису асимптотичної поведінки функцій. Широко вживається в теорії складності обчислень, інформатиці та математиці.\n![Асимптотична нотація великого О](./assets/big-o-graph.png)\n\nДжерело: [Асимптотична нотація великого О](http://bigocheatsheet.com/).\n\nНижче наведено список деяких найбільш часто використовуваних позначень нотації Ландаута їх порівняння продуктивності з різними розмірами вхідних даних.\n\n| Нотація Ландау | Обчислення для 10 елементів | Обчислення для 100 елементів | Обчислення для 1000 елементів  |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### Складність операцій в структурі даних\n\n| Структура даних        | Доступ    | Пошук    | Вставка | Видалення  | Коментарі  |\n| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |\n| **Масив**               | 1         | n         | n         | n         |           |\n| **Купа**               | n         | n         | 1         | 1         |           |\n| **Черга**               | n         | n         | 1         | 1         |           |\n| **Зв’язаний список**         | n         | n         | 1         | n         |           |\n| **Хеш-таблиця**          | -         | n         | n         | n         | У разі ідеальної хеш-функції - O(1) |\n| **Бінарне дерево пошуку**  | n         | n         | n         | n         | У разі збалансованого дерева витрати становитимуть O (log (n)) |\n| **Б-дерево**              | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Червоно-чорне дерево**      | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **АВЛ-дерево**            | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Фільтр Блума**        | -         | 1         | 1         | -         | Під час пошуку можливі помилкові спрацьовування |\n\n### Складність алгоритмів сортування масивів\n\n| Назва                  | Найкращий            | Середній             | Найгірший               | Пам'ять    | Стабільність    | Коментарі  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Сортування бульбашкою**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Так       |           |\n| **Сортування включенням**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Так       |           |\n| **Сортування вибором**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Ні        |           |\n| **Пірамідальне сортування**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Ні        |           |\n| **Сортування злиттям**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Так       |           |\n| **Швидке сортування**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | Ні        | Швидке сортування зазвичай виконується на місці з використанням O (log (n)) додаткової пам'яті |\n| **Сортування Шелла**        | n&nbsp;log(n)   | залежить від послідовності проміжків   | n&nbsp;(log(n))<sup>2</sup>  | 1         | Ні         |           |\n| **Сортування підрахунком**     | n + r           | n + r               | n + r               | n + r     | Так       | Де r - найбільше число в масиві |\n| **Сортування за розрядами**        | n * k           | n * k               | n * k               | n + k     | Так       | Де k - довжина найдовшого ключа |\n\n## Патронати проекту\n\n> Ви можете підтримати цей проект через ❤️️ [GitHub](https://github.com/sponsors/trekhleb) або ❤️️ [Patreon](https://www.patreon.com/trekhleb).\n\n[Люди, які підтримують цей проект](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.uz-UZ.md",
    "content": "# JavaScript algoritmlari va ma'lumotlar tuzilmalari\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n![repo size](https://img.shields.io/github/repo-size/trekhleb/javascript-algorithms.svg)\n\nBu repozitoriyada JavaScript-ga asoslangan ko'plab mashhur algoritmlar\nva ma'lumotlar tuzilmalarining namunalari mavjud.\n\nHar bir algoritm va ma'lumotlar tuzilmasining alohida README fayli\nbo'lib, unda tegishli tushuntirishlar va qo'shimcha o'qish uchun\nhavolalar (shu jumladan YouTube videolariga ham havolalar) mavjud.\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türkçe_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## Ma'lumotlar tuzilmalari\n\nMa'lumotlar tuzilmasi - bu kompyuterda ma'lumotlarni samarali tarzda\nolish va o'zgartirish uchun ularni tashkil etish va saqlashning ma'lum\nbir usuli. Ayniqsa, ma'lumotlar tuzilmasi ma'lumot qiymatlarining\nto'plami, ular orasidagi munosabatlar va ma'lumotlarga qo'llanilishi\nmumkin bo'lgan funksiyalar yoki operatsiyalardir.\n\n`B` - Boshlang'ich, `A` - Ilg'or\n\n- `B` [Bog'langan ro'yxat](src/data-structures/linked-list)\n- `B` [Ikki marta bog'langan ro'yxat](src/data-structures/doubly-linked-list)\n- `B` [Navbat](src/data-structures/queue)\n- `B` [Stek](src/data-structures/stack)\n- `B` [Hash jadvali](src/data-structures/hash-table)\n- `B` [Heap](src/data-structures/heap) - maksimal va minimal heap versiyalari\n- `B` [Ustuvor navbat](src/data-structures/priority-queue)\n- `A` [Trie](src/data-structures/trie)\n- `A` [Daraxt](src/data-structures/tree)\n  - `A` [Ikkilik qidiruv daraxt](src/data-structures/tree/binary-search-tree)\n  - `A` [AVL daraxt](src/data-structures/tree/avl-tree)\n  - `A` [Qizil-qora daraxt](src/data-structures/tree/red-black-tree)\n  - `A` [Segment daraxt](src/data-structures/tree/segment-tree) - min/max/sum diapazon so'rovlari bilan misollar\n  - `A` [Fenwick daraxt](src/data-structures/tree/fenwick-tree) (ikkilik indeksli daraxt)\n- `A` [Graf](src/data-structures/graph) (yo'naltirilgan hamda yo'naltirilmagan)\n- `A` [Ajratilgan to'plam](src/data-structures/disjoint-set) - union-find ma'lumotlar strukturasi yoki merge-find to'plami\n- `A` [Bloom filtri](src/data-structures/bloom-filter)\n- `A` [LRU keshi](src/data-structures/lru-cache/) - Eng kam ishlatilgan (LRU) keshi\n\n## Algoritmlar\n\nAlgoritm muammolar sinfini qanday hal qilishning aniq spetsifikatsiyasi. Bu operatsiyalar ketma-ketligini aniqlaydigan qoidalar to'plami.\n\n`B` - Boshlang'ich, `A` - Ilg'or\n\n### Mavzu bo'yicha algoritmlar\n\n- **Matematika**\n  - `B` [Bit manipulatsiyasi](src/algorithms/math/bits) - bitlarni qo'yish/olish/yangilash/tozalash, ikkilikka ko'paytirish/bo'lish, manfiy qilish va hokazo.\n  - `B` [Ikkilik suzuvchi nuqta](src/algorithms/math/binary-floating-point) - suzuvchi nuqtali sonlarning ikkilik tasviri.\n  - `B` [Faktorial](src/algorithms/math/factorial)\n  - `B` [Fibonachchi raqam](src/algorithms/math/fibonacci) - klassik va yopiq shakldagi versiyalar\n  - `B` [Asosiy omillar](src/algorithms/math/prime-factors) - tub omillarni topish va ularni Xardi-Ramanujan teoremasi yordamida sanash\n  - `B` [Birlamchilik testi](src/algorithms/math/primality-test) (sinov bo'linish usuli)\n  - `B` [Evklid algoritmi](src/algorithms/math/euclidean-algorithm) - eng katta umumiy bo'luvchini (EKUB) hisoblash\n  - `B` [Eng kichik umumiy karrali](src/algorithms/math/least-common-multiple) (EKUK)\n  - `B` [Eratosfen elagi](src/algorithms/math/sieve-of-eratosthenes) - berilgan chegaragacha barcha tub sonlarni topish\n  - `B` [Ikkining darajasimi](src/algorithms/math/is-power-of-two) - raqamning ikkining darajasi ekanligini tekshirish (sodda va bitli algoritmlar)\n  - `B` [Paskal uchburchagi](src/algorithms/math/pascal-triangle)\n  - `B` [Kompleks sonlar](src/algorithms/math/complex-number) - kompleks sonlar va ular bilan asosiy amallar\n  - `B` [Radian & Daraja](src/algorithms/math/radian) - radianlarni darajaga va orqaga aylantirish\n  - `B` [Tez ko'tarish](src/algorithms/math/fast-powering)\n  - `B` [Horner metodi](src/algorithms/math/horner-method) - polinomlarni baholash\n  - `B` [Matritsalar](src/algorithms/math/matrix) - matritsalar va asosiy matritsa operatsiyalari (ko'paytirish, transpozitsiya va boshqalar).\n  - `B` [Evklid masofasi](src/algorithms/math/euclidean-distance) - ikki nuqta/vektor/matritsa orasidagi masofa\n  - `A` [Butun sonlarni bo'lish](src/algorithms/math/integer-partition)\n  - `A` [Kvadrat ildiz](src/algorithms/math/square-root) - Nyuton metodi\n  - `A` [Liu Hui π algoritmi](src/algorithms/math/liu-hui) - N-gonlarga asoslangan π ning taxminiy hisoblari\n  - `A` [Diskret Furye transformatsiyasi](src/algorithms/math/fourier-transform) - vaqt funksiyasini (signalni) uni tashkil etuvchi chastotalarga ajratish\n- **Sets**\n  - `B` [Karteziya maxsuloti](src/algorithms/sets/cartesian-product) - bir nechta to'plamlarning ko'paytmasi\n  - `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - chekli ketma-ketlikni tasodifiy almashtirish\n  - `A` [Power Set](src/algorithms/sets/power-set) - to'plamning barcha kichik to'plamlari (bitwise, backtracking va kaskadli echimlar)\n  - `A` [Permutatsiyalar](src/algorithms/sets/permutations) (takroriyalash bilan va takroriyalashsiz)\n  - `A` [Kombinatsiyalar](src/algorithms/sets/combinations) (takroriyalash bilan va takroriyalashsiz)\n  - `A` [Eng uzun umumiy ketma-ketlik](src/algorithms/sets/longest-common-subsequence) (LCS)\n  - `A` [Eng uzun ortib boruvchi ketma-ketlik](src/algorithms/sets/longest-increasing-subsequence)\n  - `A` [Eng qisqa umumiy ketma-ketlik](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  - `A` [Knapsack muammosi](src/algorithms/sets/knapsack-problem) - \"0/1\" va \"Bir-biriga bog'lanmagan\"\n  - `A` [Maksimal kichik massiv](src/algorithms/sets/maximum-subarray) - Toʻliq kuch va dinamik dasturlash (Kadane usuli) versiyalari\n  - `A` [Kombinatsiya yig'indisi](src/algorithms/sets/combination-sum) - ma'lum summani tashkil etuvchi barcha kombinatsiyalarni topish\n- **Stringlar**\n  - `B` [Hamming masofasi](src/algorithms/string/hamming-distance) - belgilarning bir-biridan farq qiladigan pozitsiyalar soni\n  - `B` [Palindrom](src/algorithms/string/palindrome) - satrning teskari tomoni ham bir xil ekanligini tekshirish\n  - `A` [Levenshtein masofasi](src/algorithms/string/levenshtein-distance) - ikki ketma-ketlik o'rtasidagi minimal tahrirlash masofasi\n  - `A` [Knuth–Morris–Pratt Algoritmi](src/algorithms/string/knuth-morris-pratt) (KMP Algoritmi) - kichik qatorlarni qidirish (mosh keluvchi naqshni qidirish)\n  - `A` [Z Algoritmi](src/algorithms/string/z-algorithm) - kichik qatorlarni qidirish (mosh keluvchi naqshni qidirish)\n  - `A` [Rabin Karp Algoritmi](src/algorithms/string/rabin-karp) - kichik qatorlarni qidirish\n  - `A` [Eng uzun umumiy kichik matn](src/algorithms/string/longest-common-substring)\n  - `A` [Regulyar ifoda moslashuvi](src/algorithms/string/regular-expression-matching) (RegEx)\n- **Qidiruvlar**\n  - `B` [Linear qidirish](src/algorithms/search/linear-search)\n  - `B` [Jump qidirish](src/algorithms/search/jump-search) (yoki Blok qidirish) - saralangan qatorda qidirish\n  - `B` [Ikkilik qidirish](src/algorithms/search/binary-search) - saralangan qatorda qidirish\n  - `B` [Interpolatsiya qidirish](src/algorithms/search/interpolation-search) - bir tekis taqsimlangan saralangan qatorda qidirish\n- **Tartiblash**\n  - `B` [Pufakcha tartiblash](src/algorithms/sorting/bubble-sort)\n  - `B` [Tanlash tartibi](src/algorithms/sorting/selection-sort)\n  - `B` [Kiritish tartibi](src/algorithms/sorting/insertion-sort)\n  - `B` [Heap tartibi](src/algorithms/sorting/heap-sort)\n  - `B` [Birlashtirish tartibi](src/algorithms/sorting/merge-sort)\n  - `B` [Tezkor saralash](src/algorithms/sorting/quick-sort) - joyida va joyida bo'lmagan amalga oshirish\n  - `B` [Shell tartiblash](src/algorithms/sorting/shell-sort)\n  - `B` [Sanash tartibi](src/algorithms/sorting/counting-sort)\n  - `B` [Radiksli tartiblash](src/algorithms/sorting/radix-sort)\n  - `B` [Bucket tartiblash](src/algorithms/sorting/bucket-sort)\n- **Bog'langan ro'yhatlar**\n  - `B` [To'g'ri traversal](src/algorithms/linked-list/traversal)\n  - `B` [Teskari traversal](src/algorithms/linked-list/reverse-traversal)\n- **Daraxtlar**\n  - `B` [Birinchi-pastga qarab qidirish](src/algorithms/tree/depth-first-search) (Depth-First Search)\n  - `B` [Birinchi-yonga qarab qidirish](src/algorithms/tree/breadth-first-search) (Breadth-First Search)\n- **Grafiklar**\n  - `B` [Birinchi-pastga qarab qidirish](src/algorithms/graph/depth-first-search) (Depth-First Search)\n  - `B` [Birinchi-yonga qarab qidirish](src/algorithms/graph/breadth-first-search) (Breadth-First Search)\n  - `B` [Kruskal Algoritmi](src/algorithms/graph/kruskal) - og'irlikdagi yo'naltirilmagan grafik uchun Minimal kengayuvchi daraxtni (MST) topish\n  - `A` [Dijkstra Algoritmi](src/algorithms/graph/dijkstra) - grafikning bir cho'qqisidan qolgan barcha nuqtalarga eng qisqa yo'llarni topish\n  - `A` [Bellman-Ford Algoritmi](src/algorithms/graph/bellman-ford) - grafikning bir cho'qqisidan qolgan barcha nuqtalarga eng qisqa yo'llarni topish\n  - `A` [Floyd-Warshall Algoritmi](src/algorithms/graph/floyd-warshall) - grafikning barcha uchlari orasidagi eng qisqa masofalarni topish\n  - `A` [Siklni aniqlash](src/algorithms/graph/detect-cycle) - yo'naltirilgan va yo'naltirilmagan grafiklar uchun (DFS va Disjoint Set-ga asoslangan versiyalar)\n  - `A` [Prim Algoritmi](src/algorithms/graph/prim) - og'irlikdagi yo'naltirilmagan grafik uchun Minimal kengayuvchi daraxtni (MST) topish\n  - `A` [Topologik saralash](src/algorithms/graph/topological-sorting) - DFS metodi\n  - `A` [Artikulyatsiya nuqtalari](src/algorithms/graph/articulation-points) - Tarjan algoritmi (DFS asosida)\n  - `A` [Ko'priklar](src/algorithms/graph/bridges) - DFS asosidagi algoritm\n  - `A` [Eyler yo'li va Eyler sxemasi](src/algorithms/graph/eulerian-path) - Fleury algoritmi - Har bir chekkaga bir marta tashrif buyurish\n  - `A` [Gamilton sikli](src/algorithms/graph/hamiltonian-cycle) - Har bir cho'qqiga bir marta tashrif buyurish\n  - `A` [Kuchli bog'langan komponentlar](src/algorithms/graph/strongly-connected-components) - Kosaraju algoritmi\n  - `A` [Sayohatchi sotuvchi muammosi](src/algorithms/graph/travelling-salesman) - har bir shaharga tashrif buyuradigan va kelib chiqqan shaharga qaytib keladigan eng qisqa yo'l\n- **Kriptografiya**\n  - `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - polinomga asoslangan hash funktsiyasi\n  - `B` [Rail Fence Cipher](src/algorithms/cryptography/rail-fence-cipher) - xabarlarni kodlash uchun transpozitsiya shifrlash algoritmi\n  - `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - oddiy almashtirish shifridir\n  - `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - chiziqli algebraga asoslangan almashtirish shifri\n- **Machine Learning**\n  - `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - Mashinalar aslida qanday o'rganishi mumkinligini ko'rsatadigan 7 ta oddiy JS funksiyasi (forward/backward tarqalish)\n  - `B` [k-NN](src/algorithms/ml/knn) - eng yaqin qo'shnilarni tasniflash algoritmi\n  - `B` [k-Means](src/algorithms/ml/k-means) - k-Means kalsterlash algoritmi\n- **Tasvirga ishlov berish**\n  - `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - kontentga moslashuvchan rasm o'lchamini o'zgartirish algoritmi\n- **Statistikalar**\n  - `B` [Weighted Random](src/algorithms/statistics/weighted-random) - elementlarning og'irligi asosida ro'yxatdan tasodifiy elementni tanlash\n- **Evolyutsion algoritmlar**\n  - `A` [Genetik algoritm](https://github.com/trekhleb/self-parking-car-evolution) - avtoturargohni o'rgatish uchun genetik algoritm qanday qo'llanilishiga misol.\n- **Kategoriyasiz**\n  - `B` [Xanoy minorasi](src/algorithms/uncategorized/hanoi-tower)\n  - `B` [Kvadrat matritsaning aylanishi](src/algorithms/uncategorized/square-matrix-rotation) - joyidagi algoritm\n  - `B` [Sakrash o'yini](src/algorithms/uncategorized/jump-game) - orqaga qaytish, dinamik dasturlash (yuqoridan pastga + pastdan yuqoriga) va ochko'z misollar\n  - `B` [Noyob yo'llar](src/algorithms/uncategorized/unique-paths) - orqaga qaytish, dinamik dasturlash va Paskal uchburchagiga asoslangan misolla\n  - `B` [Yomg'ir teraslari](src/algorithms/uncategorized/rain-terraces) - yomg'ir suvini ushlab turish muammosi (dinamik dasturlash va qo'pol kuch versiyalari)\n  - `B` [Rekursiv zinapoya](src/algorithms/uncategorized/recursive-staircase) - yuqoriga chiqish yo'llari sonini hisoblash (4 ta echim)\n  - `B` [Aksiyalarni sotib olish va sotish uchun eng yaxshi vaqt](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - bo'linib-zabt etish va bir marta o'tish misollari\n  - `A` [N-Queens Muommosi](src/algorithms/uncategorized/n-queens)\n  - `A` [Ritsar sayohati](src/algorithms/uncategorized/knight-tour)\n\n### Paradigma bo'yicha algoritmlar\n\nAlgorithmic paradigm - bu algoritmlar sinfini loyihalashtirishga asos bo'lib xizmat qiladigan umumiy usul yoki yondashuv. Bu algoritm tushunchasidan yuqori darajadagi abstraktsiya bo'lib, algoritm kompyuter dasturi tushunchasidan yuqori darajadagi abstraktsiya bo'lgani kabi.\n\n- **Brute Force** - barcha imkoniyatlarni ko'rib chiqib va eng yaxshi echimni tanlash\n  - `B` [Chiziqli qidirish](src/algorithms/search/linear-search)\n  - `B` [Yomg'irli teraslar](src/algorithms/uncategorized/rain-terraces) - yomg'ir suvini to'plash muammosi\n  - `B` [Rekursiv zinapoya](src/algorithms/uncategorized/recursive-staircase) - cho'qqiga chiqish yo'llari sonini hisoblash\n  - `A` [Maksimal kichik massiv](src/algorithms/sets/maximum-subarray)\n  - `A` [Sayohatchi sotuvchi muammosi](src/algorithms/graph/travelling-salesman) - har bir shaharga tashrif buyuradigan va kelib chiqqan shaharga qaytib keladigan eng qisqa yo'l\n  - `A` [Diskret Furye transformatsiyasi](src/algorithms/math/fourier-transform) - vaqt funksiyasini (signalni) uni tashkil etuvchi chastotalarga ajratish\n- **Greedy** - kelajakni o'ylamasdan, hozirgi vaqtda eng yaxshi variantni tanlash\n  - `B` [Sakrash o'yini](src/algorithms/uncategorized/jump-game)\n  - `A` [Bog'lanmagan yukxalta muammosi](src/algorithms/sets/knapsack-problem)\n  - `A` [Dijkstra Algoritmi](src/algorithms/graph/dijkstra) - grafikning bir cho'qqisidan qolgan barcha nuqtalarga eng qisqa yo'llarni topish\n  - `A` [Prim Algoritmi](src/algorithms/graph/prim) - og'irlikdagi yo'naltirilmagan grafik uchun Minimal kengayuvchi daraxtni (MST) topish\n  - `A` [Kruskal Algoritmi](src/algorithms/graph/kruskal) - og'irlikdagi yo'naltirilmagan grafik uchun Minimal kengayuvchi daraxtni (MST) topish\n- **Divide and Conquer** - muammoni kichikroq qismlarga bo'lib va keyin bu qismlarni hal qilish\n\n  - `B` [Ikkilik qidiruv](src/algorithms/search/binary-search)\n  - `B` [Xanoy minorasi](src/algorithms/uncategorized/hanoi-tower)\n  - `B` [Paskal uchburchagi](src/algorithms/math/pascal-triangle)\n  - `B` [Evklid Algoritmi](src/algorithms/math/euclidean-algorithm) - eng katta umumiy bo'luvchini (EKUB) hisoblash\n  - `B` [Birlashtirish tartibi](src/algorithms/sorting/merge-sort)\n  - `B` [Tezkor saralash](src/algorithms/sorting/quick-sort)\n  - `B` [Birinchi-pastga qarab qidirish daraxti](src/algorithms/tree/depth-first-search) (DFS)\n  - `B` [Birinchi-pastga qarab qidirish grafigi](src/algorithms/graph/depth-first-search) (DFS)\n  - `B` [Matritsalar](src/algorithms/math/matrix) - turli shakldagi matritsalarni hosil qilish va kesib o'tish\n  - `B` [Sakrash o'yini](src/algorithms/uncategorized/jump-game)\n  - `B` [Tez ko'tarish](src/algorithms/math/fast-powering)\n  - `B` [Aksiyalarni sotib olish va sotish uchun eng yaxshi vaqt](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - bo'linib-zabt etish va bir marta o'tish misollari\n  - `A` [Permutatsiyalar](src/algorithms/sets/permutations) (takroriyalash bilan va takroriyalashsiz)\n  - `A` [Kombinatsiyalar](src/algorithms/sets/combinations) (takroriyalash bilan va takroriyalashsiz)\n  - `A` [Maksimal kichik massiv](src/algorithms/sets/maximum-subarray)\n\n- **Dinamik dasturlash** - ilgari topilgan kichik yechimlar yordamida yechim yaratish\n  - `B` [Fibonachchi raqam](src/algorithms/math/fibonacci)\n  - `B` [Sakrash o'yini](src/algorithms/uncategorized/jump-game)\n  - `B` [Noyob yo'llar](src/algorithms/uncategorized/unique-paths)\n  - `B` [Yomg'ir teraslari](src/algorithms/uncategorized/rain-terraces) - yomg'ir suvini to'plash muammosi\n  - `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top\n  - `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - kontentga moslashuvchan rasm o'lchamini o'zgartirish algoritmi\n  - `A` [Levenshtein masofasi](src/algorithms/string/levenshtein-distance) - ikki ketma-ketlik o'rtasidagi minimal tahrirlash masofasi\n  - `A` [Eng uzun umumiy ketma-ketlik](src/algorithms/sets/longest-common-subsequence) (LCS)\n  - `A` [Eng uzun umumiy kichik matn](src/algorithms/string/longest-common-substring)\n  - `A` [Eng uzun ortib boruvchi ketma-ketlik](src/algorithms/sets/longest-increasing-subsequence)\n  - `A` [Eng qisqa umumiy ketma-ketlik](src/algorithms/sets/shortest-common-supersequence)\n  - `A` [0/1 Knapsak muommosi](src/algorithms/sets/knapsack-problem)\n  - `A` [Butun sonlarni bo'lish](src/algorithms/math/integer-partition)\n  - `A` [Maksimal kichik massiv](src/algorithms/sets/maximum-subarray)\n  - `A` [Bellman-Ford Algoritmi](src/algorithms/graph/bellman-ford) - grafikning bir cho'qqisidan qolgan barcha nuqtalarga eng qisqa yo'llarni topish\n  - `A` [Floyd-Warshall Algoritmi](src/algorithms/graph/floyd-warshall) -grafikning barcha uchlari orasidagi eng qisqa masofalarni topish\n  - `A` [Regulyar ifoda moslashuvi](src/algorithms/string/regular-expression-matching)\n- **Backtracking** - brute forcega o'xshab, barcha mumkin bo'lgan yechimlarni generatsiya qilishga harakat qiladi, lekin har safar keyingi yechimni yaratganingizda, yechim barcha shartlarga javob beradimi yoki yo'qligini tekshirasiz va shundan keyingina keyingi yechimlarni ishlab chiqarishni davom ettirasiz. Aks holda, orqaga qaytib, yechim topishning boshqa yo'liga o'tasiz. Odatda state-space ning DFS-qidiruvi ishlatiladi.\n  - `B` [Sakrash o'yini](src/algorithms/uncategorized/jump-game)\n  - `B` [Noyob yo'llar](src/algorithms/uncategorized/unique-paths)\n  - `B` [Power Set](src/algorithms/sets/power-set) - to'plamning barcha kichik to'plamlari\n  - `A` [Gamilton sikli](src/algorithms/graph/hamiltonian-cycle) - Har bir cho'qqiga bir marta tashrif buyurish\n  - `A` [N-Queens muommosi](src/algorithms/uncategorized/n-queens)\n  - `A` [Ritsar sayohati](src/algorithms/uncategorized/knight-tour)\n  - `A` [Kombinatsiya yig'indisi](src/algorithms/sets/combination-sum) - ma'lum summani tashkil etuvchi barcha kombinatsiyalarni topish\n- **Branch & Bound** - shu paytgacha topilgan eng arzon echimdan kattaroq xarajatlarga ega qisman echimlarni bekor qilish uchun, backtracking qidiruvining har bir bosqichida topilgan eng arzon echimni eslab qoling va shu paytgacha topilgan eng arzon yechim narxidan muammoni eng kam xarajatli yechim narxining past chegarasi sifatida foydalaning. Odatda state-space daraxtining DFS o'tishi bilan birgalikda BFS traversal qo'llaniladi.\n\n## Ushbu repozitoriyadan qanday foydalanish kerak\n\n**Barcha dependensiylarni o'rnating**\n\n```\nnpm install\n```\n\n**ESLint ni ishga tushiring**\n\nKod sifatini tekshirish uchun ESLint ni ishga tushirishingiz mumkin.\n\n```\nnpm run lint\n```\n\n**Barcha testlarni ishga tushuring**\n\n```\nnpm test\n```\n\n**Testlarni nom bo'yicha ishga tushirish**\n\n```\nnpm test -- 'LinkedList'\n```\n\n**Muammolarni bartaraf qilish (Troubleshooting)**\n\nAgar linting yoki sinov muvaffaqiyatsiz bo'lsa, `node_modules` papkasini o'chirib, npm paketlarini qayta o'rnatishga harakat qiling:\n\n```\nrm -rf ./node_modules\nnpm i\n```\n\nShuningdek, to'g'ri Node versiyasidan foydalanayotganingizga ishonch hosil qiling (`>=16`). Agar Node versiyasini boshqarish uchun [nvm](https://github.com/nvm-sh/nvm) dan foydalanayotgan bo'lsangiz, loyihaning ildiz papkasidan `nvm use` ni ishga tushiring va to'g'ri versiya tanlanadi.\n\n**O'yin maydoni (Playground)**\n\n`./src/playground/playground.js` faylida ma'lumotlar strukturalari va algoritmlar bilan o'ynashingiz, `./src/playground/test/playground.test.js` faylida esa ular uchun testlar yozishingiz mumkin.\n\nShundan so'ng, playground kodingiz kutilgandek ishlashini tekshirish uchun quyidagi buyruqni ishga tushirishingiz kifoya:\n\n```\nnpm test -- 'playground'\n```\n\n## Foydali ma'lumotlar\n\n### Manbalar\n\n- [▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [✍🏻 Data Structure Sketches](https://okso.app/showcase/data-structures)\n\n### Big O Notation\n\n_Big O notation_ algoritmlarni kirish hajmi oshgani sayin ularning ishlash vaqti yoki bo'sh joy talablari qanday o'sishiga qarab tasniflash uchun ishlatiladi. Quyidagi jadvalda siz Big O notatsiyasida ko'rsatilgan algoritmlarning o'sishining eng keng tarqalgan tartiblarini topishingiz mumkin.\n\n![Big O grafiklar](./assets/big-o-graph.png)\n\nManba: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nQuyida eng ko'p qo'llaniladigan Big O notatsiyalarining ro'yxati va ularning kirish ma'lumotlarining turli o'lchamlariga nisbatan ishlashini taqqoslash keltirilgan.\n\n| Big O Notatsiya | Turi         | 10 ta element uchun hisob-kitoblar | 100 ta element uchun hisob-kitoblar | 1000 ta element uchun hisob-kitoblar |\n| --------------- | ------------ | ---------------------------------- | ----------------------------------- | ------------------------------------ |\n| **O(1)**        | O'zgarmas    | 1                                  | 1                                   | 1                                    |\n| **O(log N)**    | Logarifmik   | 3                                  | 6                                   | 9                                    |\n| **O(N)**        | Chiziqli     | 10                                 | 100                                 | 1000                                 |\n| **O(N log N)**  | n log(n)     | 30                                 | 600                                 | 9000                                 |\n| **O(N^2)**      | Kvadrat      | 100                                | 10000                               | 1000000                              |\n| **O(2^N)**      | Eksponensial | 1024                               | 1.26e+29                            | 1.07e+301                            |\n| **O(N!)**       | Faktorial    | 3628800                            | 9.3e+157                            | 4.02e+2567                           |\n\n### Ma'lumotlar tuzilmalarining operatsiyalari murakkabligi\n\n| Ma'lumotlar tuzilmalari     | Kirish | Qidirish | Kiritish | O'chirish | Izohlar                                                    |\n| --------------------------- | :----: | :------: | :------: | :-------: | :--------------------------------------------------------- |\n| **Massiv**                  |   1    |    n     |    n     |     n     |                                                            |\n| **Stak**                    |   n    |    n     |    1     |     1     |                                                            |\n| **Navbat**                  |   n    |    n     |    1     |     1     |                                                            |\n| **Bog'langan ro'yhat**      |   n    |    n     |    1     |     n     |                                                            |\n| **Hash jadval**             |   -    |    n     |    n     |     n     | Mukammal xash funksiyasi bo'lsa, xarajatlar O (1) bo'ladi. |\n| **Ikkilik qidiruv daraxti** |   n    |    n     |    n     |     n     | Balanslangan daraxt narxida O(log(n)) bo'ladi.             |\n| **B-daraxti**               | log(n) |  log(n)  |  log(n)  |  log(n)   |                                                            |\n| **Qizil-qora daraxt**       | log(n) |  log(n)  |  log(n)  |  log(n)   |                                                            |\n| **AVL Daraxt**              | log(n) |  log(n)  |  log(n)  |  log(n)   |                                                            |\n| **Bloom filtri**            |   -    |    1     |    1     |     -     | Qidiruv paytida noto'g'ri pozitivlar bo'lishi mumkin       |\n\n### Massivlarni saralash algoritmlarining murakkabligi\n\n| Nomi                      |  Eng yaxshi   |          O'rta          |          Eng yomon          | Xotira | Barqaror | Izohlar                                                                      |\n| ------------------------- | :-----------: | :---------------------: | :-------------------------: | :----: | :------: | :--------------------------------------------------------------------------- |\n| **Pufakcha tartiblash**   |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |    Ha    |                                                                              |\n| **Kiritish tartibi**      |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |    Ha    |                                                                              |\n| **Tanlash tartibi**       | n<sup>2</sup> |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |   Yo'q   |                                                                              |\n| **Heap tartibi**          | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   1    |   Yo'q   |                                                                              |\n| **Birlashtirish tartibi** | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   n    |    Ha    |                                                                              |\n| **Tezkor saralash**       | n&nbsp;log(n) |      n&nbsp;log(n)      |        n<sup>2</sup>        | log(n) |   Yo'q   | Tezkor saralash odatda O(log(n)) stek maydoni bilan joyida amalga oshiriladi |\n| **Shell tartiblash**      | n&nbsp;log(n) | depends on gap sequence | n&nbsp;(log(n))<sup>2</sup> |   1    |   Yo'q   |                                                                              |\n| **Sanash tartibi**        |     n + r     |          n + r          |            n + r            | n + r  |    Ha    | r - massivdagi eng katta raqam                                               |\n| **Radiksli tartiblash**   |    n \\* k     |         n \\* k          |           n \\* k            | n + k  |    Ha    | k - eng uzun kalitning uzunligi                                              |\n\n## Loyihani qo'llab-quvvatlovchilar\n\n> Siz ushbu loyihani ❤️️ [GitHub](https://github.com/sponsors/trekhleb) yoki ❤️️ [Patreon](https://www.patreon.com/trekhleb) orqali qo'llab-quvvatlashingiz mumkin.\n\n[Ushbu loyihani qo'llab-quvvatlagan odamlar](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`\n\n## Muallif\n\n[@trekhleb](https://trekhleb.dev)\n\nA few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.vi-VN.md",
    "content": "# JavaScript Thuật Toán và Cấu Trúc Dữ Liệu\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\nRepository này bao gồm nhiều ví dụ thuật toán và cấu trúc dữ liệu phổ biến\ndựa trên Javascript.\n\nMố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\nliên quan để đọc thêm (bao gồm cả những videos trên Youtube).\n\n_Đọc bằng ngôn ngữ khác:_\n[_English_](README.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md)\n[_עברית_](README.he-IL.md)\n\n## Cấu Trúc Dữ Liệu\n\nCấ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ể\nđượ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\ncá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\ncho dữ liệu.\n\n`B` - Cơ bản, `A` - Nâng cao\n\n* `B` [Danh sách liên kết](src/data-structures/linked-list)\n* `B` [Danh sách liên kết đôi](src/data-structures/doubly-linked-list)\n* `B` [Hàng đợi](src/data-structures/queue)\n* `B` [Ngăn xếp](src/data-structures/stack)\n* `B` [Bảng băm](src/data-structures/hash-table)\n* `B` [Đống](src/data-structures/heap) - max và min heap\n* `B` [Hàng đợi ưu tiên](src/data-structures/priority-queue)\n* `A` [Cây tiền tố](src/data-structures/trie)\n* `A` [Cây](src/data-structures/tree)\n  * `A` [Cây tìm kiếm nhị phân](src/data-structures/tree/binary-search-tree)\n  * `A` [Cây AVL](src/data-structures/tree/avl-tree)\n  * `A` [Cây đỏ đen](src/data-structures/tree/red-black-tree)\n  * `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\n  * `A` [CÂy Fenwick](src/data-structures/tree/fenwick-tree) (Cây chỉ mục nhị phân)\n* `A` [Đồ thị](src/data-structures/graph) (có hướng và vô hướng)\n* `A` [Tập hợp không giao nhau](src/data-structures/disjoint-set)\n* `A` [Bộ lọc Bloom](src/data-structures/bloom-filter)\n\n## Thuật Toán\n\nThuậ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\nquy tắc xác định chính xác một chuỗi phép toán.\n\n`B` - Cơ bản, `A` - Nâng cao\n\n### Thuật toán theo chủ đề\n\n* **Toán**\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,...\n  * `B` [Giai thừa](src/algorithms/math/factorial)\n  * `B` [Số Fibonacci](src/algorithms/math/fibonacci) - cổ điển và dạng đóng\n  * `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\n  * `B` [Kiểm tra tính nguyên tố](src/algorithms/math/primality-test) (phân chia thử nghiệm)\n  * `B` [Thuật toán Euclid](src/algorithms/math/euclidean-algorithm) - tính ước số chung lớn nhất (GCD)\n  * `B` [Bội số chung nhỏ nhất](src/algorithms/math/least-common-multiple) (LCM)\n  * `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\n  * `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)\n  * `B` [Tam giác Pascal](src/algorithms/math/pascal-triangle)\n  * `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\n  * `B` [Radian & độ](src/algorithms/math/radian) - chuyển đổi giữa đơn vị radian và độ\n  * `B` [Tính nhanh lũy thừa](src/algorithms/math/fast-powering)\n  * `B` [Phương pháp Horner's](src/algorithms/math/horner-method) - tính giá trị đa thức\n  * `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ị,...)\n  * `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\n  * `A` [Phân hoạch](src/algorithms/math/integer-partition)\n  * `A` [Căn bậc hai](src/algorithms/math/square-root) - phương pháp Newton\n  * `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\n  * `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 đó\n* **Tập hợp**\n  * `B` [Tích Đề-các](src/algorithms/sets/cartesian-product) - tích của nhiều tập hợp\n  * `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\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)\n  * `A` [Hoán vị](src/algorithms/sets/permutations) (lặp và không lặp)\n  * `A` [Tổ hợp](src/algorithms/sets/combinations) (lặp và không lặp)\n  * `A` [Dãy con chung dài nhất](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Dãy con chung tăng dần dài nhất](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Dãy con chung ngắn nhất](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [Bài toán xếp ba lô](src/algorithms/sets/knapsack-problem) - dạng 0-1 và không bị chặn\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)\n  * `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ể\n* **Chuỗi**\n  * `B` [Khoảng cách Hamming](src/algorithms/string/hamming-distance) - số các vị trí các ký hiệu khác nhau\n  * `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ự\n  * `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)\n  * `A` [Thuật toán Z](src/algorithms/string/z-algorithm) - tìm chuỗi con (đối sánh mẫu)\n  * `A` [Thuật toán Rabin Karp](src/algorithms/string/rabin-karp) - tìm chuỗi con\n  * `A` [Xâu con chung dài nhất](src/algorithms/string/longest-common-substring)\n  * `A` [Phối biểu thức chính quy](src/algorithms/string/regular-expression-matching)\n* **Tìm kiếm**\n  * `B` [Tìm kiếm tuyến tính](src/algorithms/search/linear-search)\n  * `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\n  * `B` [Tìm kiếm nhị phân](src/algorithms/search/binary-search) - tìm kiếm trong mảng đã sắp xếp\n  * `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\n* **Sắp xếp**\n  * `B` [Sắp xếp nổi bọt](src/algorithms/sorting/bubble-sort)\n  * `B` [Sắp xếp chọn](src/algorithms/sorting/selection-sort)\n  * `B` [Sắp xếp chèn](src/algorithms/sorting/insertion-sort)\n  * `B` [Sắp xếp vun đống](src/algorithms/sorting/heap-sort)\n  * `B` [Sắp xếp trộn](src/algorithms/sorting/merge-sort)\n  * `B` [Sắp xếp nhanh](src/algorithms/sorting/quick-sort) - Tại chỗ và không tại chỗ\n  * `B` [Shellsort](src/algorithms/sorting/shell-sort)\n  * `B` [Sắp xếp đếm](src/algorithms/sorting/counting-sort)\n  * `B` [Sắp xếp theo cơ số](src/algorithms/sorting/radix-sort)\n* **Danh sách liên kết**\n  * `B` [Di chuyển chính hướng](src/algorithms/linked-list/traversal)\n  * `B` [Di chuyển ngược hướng](src/algorithms/linked-list/reverse-traversal)\n* **Cây**\n  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)\n* **Đồ thị**\n  * `B` [Tìm kiếm theo chiều sâu](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [Tìm kiếm theo chiều rộng](src/algorithms/graph/breadth-first-search) (BFS)\n  * `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ố\n  * `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\n  * `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ị\n  * `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\n  * `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)\n  * `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ố\n  * `A` [Sắp xếp tô pô](src/algorithms/graph/topological-sorting) - phương pháp DFS\n  * `A` [Điểm khớp](src/algorithms/graph/articulation-points) - Thuật toán Tarjan (dựa trên DFS)\n  * `A` [Cầu nối](src/algorithms/graph/bridges) - dựa trên DFS\n  * `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\n  * `A` [Chu trình Hamilton](src/algorithms/graph/hamiltonian-cycle) - đi qua các đỉnh chỉ một lần duy nhất\n  * `A` [Các thành phần kết nối chặt](src/algorithms/graph/strongly-connected-components) - Thuật toán Kosaraju\n  * `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\n* **Mật mã học**\n  * `B` [Băm đa thức](src/algorithms/cryptography/polynomial-hash) - lăn hàm băm dựa trên đa thức\n  * `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\n  * `B` [Mật mã Caesar](src/algorithms/cryptography/caesar-cipher) - mật mã chuyển vị đơn giản\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\n* **Học máy**\n  * `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)\n  * `B` [k-NN](src/algorithms/ml/knn) - thuật toán phân loại k láng giềng gần nhất\n  * `B` [k-Means](src/algorithms/ml/k-means) - thuật toán phân cụm k-Means\n* **Khác**\n  * `B` [Tháp Hà Nội](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Xoay ma trận vuông](src/algorithms/uncategorized/square-matrix-rotation) - thuật toán tại chỗ\n  * `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\n  * `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\n  * `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)\n  * `B` [Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách lên đến đỉnh (4 lời giải)\n  * `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\n  * `A` [Bài toán n quân hậu](src/algorithms/uncategorized/n-queens)\n  * `A` [Mã đi tuần](src/algorithms/uncategorized/knight-tour)\n\n### Thuật toán theo mẫu hình\n\nMẫ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\nlớ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ư\nmộ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.\n\n* **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\n  * `B` [Tìm kiếm tuyến tính](src/algorithms/search/linear-search)\n  * `B` [Thu thập nước mưa](src/algorithms/uncategorized/rain-terraces) - bài toán bẫy nước mưa\n  * `B` [Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách lên đến đỉnh\n  * `A` [Mảng con lớn nhất](src/algorithms/sets/maximum-subarray)\n  * `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\n  * `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 đó\n* **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\n  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)\n  * `A` [Bài xếp ba lô không bị chặn](src/algorithms/sets/knapsack-problem)\n  * `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\n  * `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ố\n  * `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ố\n* **Chia để trị** - chia vấn đề thành các phần nhỏ hơn rồi giải quyết các phần đó\n  * `B` [Tìm kiếm nhị phân](src/algorithms/search/binary-search)\n  * `B` [Tháp Hà Nội](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [Tam giác Pascal](src/algorithms/math/pascal-triangle)\n  * `B` [Thuật toán Euclid](src/algorithms/math/euclidean-algorithm) - tính ước số chung lớn nhất\n  * `B` [Sắp xếp trộn](src/algorithms/sorting/merge-sort)\n  * `B` [Sắp xếp nhanh](src/algorithms/sorting/quick-sort)\n  * `B` [Cây tìm kiếm theo chiều sâu](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [Đồ thị tìm kiếm theo chiều sâu](src/algorithms/graph/depth-first-search) (DFS)\n  * `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\n  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)\n  * `B` [Tính nhanh lũy thừa](src/algorithms/math/fast-powering)\n  * `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\n  * `A` [Hoán vị](src/algorithms/sets/permutations) (lặp và không lặp)\n  * `A` [Tổ hợp](src/algorithms/sets/combinations) (lặp và không lặp)\n* **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\n  * `B` [Số Fibonacci](src/algorithms/math/fibonacci)\n  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)\n  * `B` [Đường đi độc nhất](src/algorithms/uncategorized/unique-paths)\n  * `B` [Thu thập nước mưa](src/algorithms/uncategorized/rain-terraces) - bài toán bẫy nước mưa\n  * `B` [Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách lên đến đỉnh\n  * `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ự\n  * `A` [Dãy con chung dài nhất](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [Xâu con chung dài nhất](src/algorithms/string/longest-common-substring)\n  * `A` [Dãy con chung tăng dần dài nhất](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [Dãy con chung ngắn nhất](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [Bài xếp ba lô dạng 0-1](src/algorithms/sets/knapsack-problem)\n  * `A` [Integer Partition](src/algorithms/math/integer-partition)\n  * `A` [Mảng con lớn nhất](src/algorithms/sets/maximum-subarray)\n  * `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ị\n  * `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\n  * `A` [Phối biểu thức chính quy](src/algorithms/string/regular-expression-matching)\n* **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,\nbạ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.\nNế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.\n  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)\n  * `B` [Đường đi độc nhất](src/algorithms/uncategorized/unique-paths)\n  * `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\n  * `A` [Chu trình Hamilton](src/algorithms/graph/hamiltonian-cycle) - đi qua các đỉnh một lần duy nhất\n  * `A` [Bài toán n quân hậu](src/algorithms/uncategorized/n-queens)\n  * `A` [Mã đi tuần](src/algorithms/uncategorized/knight-tour)\n  * `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ể\n* **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,\nsử 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\nmộ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.\nThô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.\n\n## Hướng dẫn sử dụng repository\n\n**Cài đặt tất cả các phụ thuộc**\n```\nnpm install\n```\n\n**Chạy ESLint**\n\nBạn có thể muốn chạy nó để kiểm tra chất lượng code.\n\n```\nnpm run lint\n```\n\n**Chạy tất cả các kiểm thử**\n```\nnpm test\n```\n\n**Chạy kiểm thử theo tên**\n```\nnpm test -- 'LinkedList'\n```\n\n**Sân chơi**\n\nBạ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`\nvà viết các bài kiểm thử cho nó ở `./src/playground/__test__/playground.test.js`.\n\nSau đó, 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:\n\n```\nnpm test -- 'playground'\n```\n\n## Thông tin hữu ích\n\n### Tham khảo\n\n[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### Kí hiệu O lớn\n\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.\nTrê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.\n\n![Đồ thị O lớn](./assets/big-o-graph.png)\n\nNguồn: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\nDướ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.\n\n| 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ử   |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### Độ phức tạp của các phép toán cấu trúc dữ liệu\n\n| Cấu trúc dữ liệu        | Truy cập   | Tìm kiếm    | Chèn | Xóa  | Bình luận  |\n| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |\n| **Mảng**               | 1         | n         | n         | n         |           |\n| **Ngăn xếp**               | n         | n         | 1         | 1         |           |\n| **Hàng đợi**               | n         | n         | 1         | 1         |           |\n| **Danh sách liên kết**         | n         | n         | 1         | n         |           |\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) |\n| **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)) |\n| **Cây B**              | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Cây đỏ đen**      | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Cây AVL**            | log(n)    | log(n)    | log(n)    | log(n)    |           |\n| **Bộ lọc Bloom**        | -         | 1         | 1         | -         | Có thể có kết quả dương tính giả trong khi tìm kiếm  |\n\n### Độ phức tạp của các thuật toán sắp xếp mảng\n\n| Tên                  | Tốt nhất            | Trung bình             | Tệ nhất              | Bộ nhớ    | Ổn định    | Bình luận  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Sắp xếp nổi bọt**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Có       |           |\n| **Sắp xếp chèn**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Có       |           |\n| **Sắp xếp chọn**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Không        |           |\n| **Sắp xếp vun đống**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Không        |           |\n| **Sắp xếp trộn**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Có       |           |\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 ngăn xếp O (log (n))  |\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         |           |\n| **Sắp xếp đếm**     | n + r           | n + r               | n + r               | n + r     | Có       | r - số lớn nhất trong mảng |\n| **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 |\n\n## Project Backers\n\n> 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).\n\n[Những người đang ủng hộ dự án này](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0`\n"
  },
  {
    "path": "README.zh-CN.md",
    "content": "# JavaScript 算法与数据结构\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\n本仓库包含了多种基于 JavaScript 的算法与数据结构。\n\n每种算法和数据结构都有自己的 README，包含相关说明和链接，以便进一步阅读 (还有 YouTube 视频) 。\n\n_Read this in other languages:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_繁體中文_](README.zh-TW.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## 数据结构\n\n数据结构是在计算机中组织和存储数据的一种特殊方式，使得数据可以高效地被访问和修改。更确切地说，数据结构是数据值的集合，表示数据之间的关系，也包括了作用在数据上的函数或操作。\n\n`B` - 初学者， `A` - 进阶\n\n* `B` [链表](src/data-structures/linked-list/README.zh-CN.md)\n* `B` [双向链表](src/data-structures/doubly-linked-list/README.zh-CN.md)\n* `B` [队列](src/data-structures/queue/README.zh-CN.md)\n* `B` [栈](src/data-structures/stack/README.zh-CN.md)\n* `B` [哈希表(散列)](src/data-structures/hash-table/README.zh-CN.md)\n* `B` [堆](src/data-structures/heap/README.zh-CN.md) - 最大堆 & 最小堆\n* `B` [优先队列](src/data-structures/priority-queue/README.zh-CN.md)\n* `A` [字典树](src/data-structures/trie/README.zh-CN.md)\n* `A` [树](src/data-structures/tree/README.zh-CN.md)\n  * `A` [二叉查找树](src/data-structures/tree/binary-search-tree)\n  * `A` [AVL 树](src/data-structures/tree/avl-tree)\n  * `A` [红黑树](src/data-structures/tree/red-black-tree)\n  * `A` [线段树](src/data-structures/tree/segment-tree) - 使用 `最小/最大/总和` 范围查询示例\n  * `A` [树状数组](src/data-structures/tree/fenwick-tree) (二叉索引树)\n* `A` [图](src/data-structures/graph/README.zh-CN.md) (有向图与无向图)\n* `A` [并查集](src/data-structures/disjoint-set)\n* `A` [布隆过滤器](src/data-structures/bloom-filter)\n\n## 算法\n\n算法是如何解决一类问题的明确规范。算法是一组精确定义操作序列的规则。\n\n`B` - 初学者， `A` - 进阶\n\n### 算法主题\n\n* **数学**\n  * `B` [位运算](src/algorithms/math/bits) - set/get/update/clear 位、乘以/除以二进制位 、变负等\n  * `B` [阶乘](src/algorithms/math/factorial/README.zh-CN.md)\n  * `B` [斐波那契数](src/algorithms/math/fibonacci) - `经典` 和 `闭式` 版本\n  * `B` [素数检测](src/algorithms/math/primality-test) (排除法)\n  * `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD)\n  * `B` [最小公倍数](src/algorithms/math/least-common-multiple) (LCM)\n  * `B` [素数筛](src/algorithms/math/sieve-of-eratosthenes) - 查找任意给定范围内的所有素数\n  * `B` [判断 2 次方数](src/algorithms/math/is-power-of-two) - 检查数字是否为 2 的幂 (原生和按位算法)\n  * `B` [杨辉三角形](src/algorithms/math/pascal-triangle)\n  * `B` [复数](src/algorithms/math/complex-number) - 复数及其基本运算\n  * `B` [弧度和角](src/algorithms/math/radian) - 弧度与角的相互转换\n  * `B` [快速算次方](src/algorithms/math/fast-powering)\n  * `A` [整数拆分](src/algorithms/math/integer-partition)\n  * `A` [割圆术](src/algorithms/math/liu-hui) - 基于 N-gons 的近似 π 计算\n  * `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率\n* **集合**\n  * `B` [笛卡尔积](src/algorithms/sets/cartesian-product) - 多集合结果\n  * `A` [洗牌算法](src/algorithms/sets/fisher-yates) - 随机置换有限序列\n  * `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集\n  * `A` [排列](src/algorithms/sets/permutations) (有/无重复)\n  * `A` [组合](src/algorithms/sets/combinations) (有/无重复)\n  * `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [最短公共父序列](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * `A` [背包问题](src/algorithms/sets/knapsack-problem) - `0/1` 和 `无边界` 问题\n  * `A` [最大子数列问题](src/algorithms/sets/maximum-subarray) - `BF 算法` 和 `动态规划`\n  * `A` [组合求和](src/algorithms/sets/combination-sum) - 查找形成特定总和的所有组合\n* **字符串**\n  * `B` [汉明距离](src/algorithms/string/hamming-distance) - 符号不同的位置数\n  * `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离\n  * `A` [Knuth–Morris–Pratt 算法](src/algorithms/string/knuth-morris-pratt) KMP 算法 - 子串搜索 (模式匹配)\n  * `A` [字符串快速查找](src/algorithms/string/z-algorithm) - 子串搜索 (模式匹配)\n  * `A` [Rabin Karp 算法](src/algorithms/string/rabin-karp) - 子串搜索\n  * `A` [最长公共子串](src/algorithms/string/longest-common-substring)\n  * `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching)\n* **搜索**\n  * `B` [线性搜索](src/algorithms/search/linear-search)\n  * `B` [跳转搜索/块搜索](src/algorithms/search/jump-search) - 搜索有序数组\n  * `B` [二分查找](src/algorithms/search/binary-search) - 搜索有序数组\n  * `B` [插值搜索](src/algorithms/search/interpolation-search) - 搜索均匀分布的有序数组\n* **排序**\n  * `B` [冒泡排序](src/algorithms/sorting/bubble-sort)\n  * `B` [选择排序](src/algorithms/sorting/selection-sort)\n  * `B` [插入排序](src/algorithms/sorting/insertion-sort)\n  * `B` [堆排序](src/algorithms/sorting/heap-sort)\n  * `B` [归并排序](src/algorithms/sorting/merge-sort)\n  * `B` [快速排序](src/algorithms/sorting/quick-sort) - in-place (原地) 和 non-in-place 版本\n  * `B` [希尔排序](src/algorithms/sorting/shell-sort)\n  * `B` [计数排序](src/algorithms/sorting/counting-sort)\n  * `B` [基数排序](src/algorithms/sorting/radix-sort)\n* **链表**\n  - `B` [正向遍历](src/algorithms/linked-list/traversal)\n  - `B` [反向遍历](src/algorithms/linked-list/reverse-traversal)\n* **树**\n  * `B` [深度优先搜索](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [广度优先搜索](src/algorithms/tree/breadth-first-search) (BFS)\n* **图**\n  * `B` [深度优先搜索](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [广度优先搜索](src/algorithms/graph/breadth-first-search) (BFS)\n  * `B` [克鲁斯克尔演算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST)\n  * `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到图中所有顶点的最短路径\n  * `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到图中所有顶点的最短路径\n  * `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对 之间的最短路径\n  * `A` [判圈算法](src/algorithms/graph/detect-cycle) - 对于有向图和无向图 (基于 DFS 和不相交集的版本)\n  * `A` [普林演算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST)\n  * `A` [拓扑排序](src/algorithms/graph/topological-sorting) - DFS 方法\n  * `A` [关节点](src/algorithms/graph/articulation-points) - Tarjan 算法 (基于 DFS)\n  * `A` [桥](src/algorithms/graph/bridges) - 基于 DFS 的算法\n  * `A` [欧拉回径与一笔画问题](src/algorithms/graph/eulerian-path) - Fleury 的算法 - 一次访问每个边\n  * `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次\n  * `A` [强连通分量](src/algorithms/graph/strongly-connected-components) - Kosaraju 算法\n  * `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市\n* **加密**\n  * `B` [多项式 hash](src/algorithms/cryptography/polynomial-hash) - 基于多项式的 rolling hash 函数\n* **机器学习**\n  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) -7个简单的JS函数，说明机器如何实际学习（向前/向后传播）\n* **未分类**\n  * `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [旋转矩阵](src/algorithms/uncategorized/square-matrix-rotation) - 原地算法\n  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - 回溯,、动态编程 (自上而下+自下而上) 和贪婪的例子\n  * `B` [独特(唯一) 路径](src/algorithms/uncategorized/unique-paths) - 回溯、动态编程和基于 Pascal 三角形的例子\n  * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱捕雨水问题 (动态编程和暴力版本)\n  * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案)\n  * `A` [八皇后问题](src/algorithms/uncategorized/n-queens)\n  * `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour)\n\n### 算法范式\n\n算法范式是一种通用方法，基于一类算法的设计。这是比算法更高的抽象，就像算法是比计算机程序更高的抽象。\n\n* **BF 算法** - `查找/搜索` 所有可能性并选择最佳解决方案\n  * `B` [线性搜索](src/algorithms/search/linear-search)\n  * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱导雨水问题\n  * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案)\n  * `A` [最大子数列](src/algorithms/sets/maximum-subarray)\n  * `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市\n  * `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率\n* **贪心法** - 在当前选择最佳选项，不考虑以后情况\n  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)\n  * `A` [背包问题](src/algorithms/sets/knapsack-problem)\n  * `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径\n  * `A` [普里姆算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST)\n  * `A` [克鲁斯卡尔算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST)\n* **分治法** - 将问题分成较小的部分，然后解决这些部分\n  * `B` [二分查找](src/algorithms/search/binary-search)\n  * `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower)\n  * `B` [杨辉三角形](src/algorithms/math/pascal-triangle)\n  * `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD)\n  * `B` [归并排序](src/algorithms/sorting/merge-sort)\n  * `B` [快速排序](src/algorithms/sorting/quick-sort)\n  * `B` [树深度优先搜索](src/algorithms/tree/depth-first-search) (DFS)\n  * `B` [图深度优先搜索](src/algorithms/graph/depth-first-search) (DFS)\n  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)\n  * `B` [快速算次方](src/algorithms/math/fast-powering)\n  * `A` [排列](src/algorithms/sets/permutations) (有/无重复)\n  * `A` [组合](src/algorithms/sets/combinations) (有/无重复)\n* **动态规划(Dynamic programming)** - 使用以前找到的子解决方案构建解决方案\n  * `B` [斐波那契数](src/algorithms/math/fibonacci)\n  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)\n  * `B` [独特路径](src/algorithms/uncategorized/unique-paths)\n  * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 疏导雨水问题\n  * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案)\n  * `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离\n  * `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * `A` [最长公共子串](src/algorithms/string/longest-common-substring)\n  * `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence)\n  * `A` [最短公共子序列](src/algorithms/sets/shortest-common-supersequence)\n  * `A` [0-1背包问题](src/algorithms/sets/knapsack-problem)\n  * `A` [整数拆分](src/algorithms/math/integer-partition)\n  * `A` [最大子数列](src/algorithms/sets/maximum-subarray)\n  * `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径\n  * `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对之间的最短路径\n  * `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching)\n* **回溯法** - 类似于 `BF 算法` 试图产生所有可能的解决方案，但每次生成解决方案测试如果它满足所有条件，那么只有继续生成后续解决方案。否则回溯并继续寻找不同路径的解决方案。\n  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)\n  * `B` [独特路径](src/algorithms/uncategorized/unique-paths)\n  * `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集\n  * `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次\n  * `A` [八皇后问题](src/algorithms/uncategorized/n-queens)\n  * `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour)\n  * `A` [组合求和](src/algorithms/sets/combination-sum) - 从规定的总和中找出所有的组合\n* **Branch & Bound** - 记住在回溯搜索的每个阶段找到的成本最低的解决方案，并使用到目前为止找到的成本最小值作为下限。以便丢弃成本大于最小值的解决方案。通常，使用 BFS 遍历以及状态空间树的 DFS 遍历。\n\n## 如何使用本仓库\n\n**安装依赖**\n```\nnpm install\n```\n\n**运行 ESLint**\n\n检查代码质量\n\n```\nnpm run lint\n```\n\n**执行测试**\n\n```\nnpm test\n```\n\n**按照名称执行测试**\n```\nnpm test -- 'LinkedList'\n```\n\n**Playground**\n\n你可以在 `./src/playground/playground.js` 文件中操作数据结构与算法，并在 `./src/playground/__test__/playground.test.js` 中编写测试。\n\n然后，只需运行以下命令来测试你的 Playground 是否无误:\n\n```\nnpm test -- 'playground'\n```\n\n## 有用的信息\n\n### 引用\n\n[▶ YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### 大O符号\n\n大O符号中指定的算法的增长顺序。\n\n![Big O graphs](./assets/big-o-graph.png)\n\n源: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\n以下是一些最常用的 大O标记法 列表以及它们与不同大小输入数据的性能比较。\n\n| 大O标记法      | 计算10个元素                 | 计算100个元素                 | 计算1000个元素                  |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### 数据结构操作的复杂性\n\n| 数据结构       |  连接  |  查找  |  插入  |  删除  | 备注 |\n| -------------- | :----: | :----: | :----: | :----: | ---- |\n| **数组**       |   1    |   n    |   n    |   n    |      |\n| **栈**         |   n    |   n    |   1    |   1    |      |\n| **队列**       |   n    |   n    |   1    |   1    |      |\n| **链表**       |   n    |   n    |   1    |   1    |      |\n| **哈希表**     |   -    |   n    |   n    |   n    | 在完全哈希函数情况下，复杂度是 O(1） |\n| **二分查找树** |   n    |   n    |   n    |   n    | 在平衡树情况下，复杂度是 O(log(n)) |\n| **B 树**       | log(n) | log(n) | log(n) | log(n) |      |\n| **红黑树**     | log(n) | log(n) | log(n) | log(n) |      |\n| **AVL 树**     | log(n) | log(n) | log(n) | log(n) |      |\n| **布隆过滤器** |   -    |   1    |   1    | - | 存在一定概率的判断错误（误判成存在） |\n\n### 数组排序算法的复杂性\n\n| 名称                  | 最优      | 平均      | 最坏          | 内存      | 稳定      | 备注                  |\n| --------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: | --------------------- |\n| **冒泡排序**          | n         | n^2       | n^2           | 1         | Yes       |                       |\n| **插入排序**          | n         | n^2       | n^2           | 1         | Yes       |                       |\n| **选择排序**          | n^2       | n^2       | n^2           | 1         | No        |                       |\n| **堆排序**            | n log(n)  | n log(n)  | n log(n)      | 1         | No        |                       |\n| **归并排序**          | n log(n)  | n log(n)  | n log(n)      | n         | Yes       |                       |\n| **快速排序**          | n log(n)  | n log(n)  | n^2           | log(n)    | No        | 在 in-place 版本下，内存复杂度通常是 O(log(n)) |\n| **希尔排序**          | n log(n)  | 取决于差距序列   | n (log(n))^2  | 1         | No        |  |\n| **计数排序**          | n + r     | n + r     | n + r         | n + r     | Yes       | r - 数组里最大的数    |\n| **基数排序**          | n * k     | n * k     | n * k         | n + k     | Yes       | k - 最长 key 的升序   |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "README.zh-TW.md",
    "content": "# JavaScript 演算法與資料結構\n\n[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)\n[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)\n\n這個知識庫包含許多 JavaScript 的資料結構與演算法的基礎範例。\n每個演算法和資料結構都有其個別的文件，內有相關的解釋以及更多相關的文章或Youtube影片連結。\n\n_Read this in other languages:_\n[_English_](https://github.com/trekhleb/javascript-algorithms/),\n[_简体中文_](README.zh-CN.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_Polski_](README.pl-PL.md),\n[_Français_](README.fr-FR.md),\n[_Español_](README.es-ES.md),\n[_Português_](README.pt-BR.md),\n[_Русский_](README.ru-RU.md),\n[_Türk_](README.tr-TR.md),\n[_Italiana_](README.it-IT.md),\n[_Bahasa Indonesia_](README.id-ID.md),\n[_Українська_](README.uk-UA.md),\n[_Arabic_](README.ar-AR.md),\n[_Tiếng Việt_](README.vi-VN.md),\n[_Deutsch_](README.de-DE.md),\n[_Uzbek_](README.uz-UZ.md)\n[_עברית_](README.he-IL.md)\n\n## 資料結構\n\n資料結構是一個電腦用來組織和排序資料的特定方式，透過這樣的方式資料可以有效率地被讀取以及修改。更精確地說，一個資料結構是一個資料值的集合、彼此間的關係，函數或者運作可以應用於資料上。\n\n* [鏈結串列](src/data-structures/linked-list)\n* [貯列](src/data-structures/queue)\n* [堆疊](src/data-structures/stack)\n* [雜湊表](src/data-structures/hash-table)\n* [堆](src/data-structures/heap)\n* [優先貯列](src/data-structures/priority-queue)\n* [字典樹](src/data-structures/trie)\n* [樹](src/data-structures/tree)\n  * [二元搜尋樹](src/data-structures/tree/binary-search-tree)\n  * [AVL樹](src/data-structures/tree/avl-tree)\n  * [紅黑樹](src/data-structures/tree/red-black-tree)\n* [圖](src/data-structures/graph) (有向跟無向皆包含)\n* [互斥集](src/data-structures/disjoint-set)\n\n## 演算法\n\n演算法是一個如何解決一類問題的非模糊規格。演算法是一個具有精確地定義了一系列運作的規則的集合\n\n### 演算法議題分類\n\n* **數學類**\n  * [階層](src/algorithms/math/factorial)\n  * [費伯納西數列](src/algorithms/math/fibonacci)\n  * [Primality Test](src/algorithms/math/primality-test) (排除法)\n  * [歐幾里得算法](src/algorithms/math/euclidean-algorithm) - 計算最大公因數 (GCD)\n  * [最小公倍數](src/algorithms/math/least-common-multiple) (LCM)\n  * [整數拆分](src/algorithms/math/integer-partition)\n* **集合**\n  * [笛卡爾積](src/algorithms/sets/cartesian-product) - 多個集合的乘積\n  * [冪集合](src/algorithms/sets/power-set) - 所有集合的子集合\n  * [排列](src/algorithms/sets/permutations) (有/無重複)\n  * [组合](src/algorithms/sets/combinations) (有/無重複)\n  * [洗牌算法](src/algorithms/sets/fisher-yates) - 隨機置換一有限序列\n  * [最長共同子序列](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * [最長遞增子序列](src/algorithms/sets/longest-increasing-subsequence)\n  * [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)\n  * [背包問題](src/algorithms/sets/knapsack-problem) - \"0/1\" and \"Unbound\" ones\n  * [最大子序列問題](src/algorithms/sets/maximum-subarray) - 暴力法以及動態編程的(Kadane's)版本\n* **字串**\n  * [萊文斯坦距離](src/algorithms/string/levenshtein-distance) - 兩序列間的最小編輯距離\n  * [漢明距離](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different\n  * [KMP 演算法](src/algorithms/string/knuth-morris-pratt) - 子字串搜尋\n  * [Rabin Karp 演算法](src/algorithms/string/rabin-karp) - 子字串搜尋\n  * [最長共通子序列](src/algorithms/string/longest-common-substring)\n* **搜尋**\n  * [二元搜尋](src/algorithms/search/binary-search)\n* **排序**\n  * [氣泡排序](src/algorithms/sorting/bubble-sort)\n  * [選擇排序](src/algorithms/sorting/selection-sort)\n  * [插入排序](src/algorithms/sorting/insertion-sort)\n  * [堆排序](src/algorithms/sorting/heap-sort)\n  * [合併排序](src/algorithms/sorting/merge-sort)\n  * [快速排序](src/algorithms/sorting/quick-sort)\n  * [希爾排序](src/algorithms/sorting/shell-sort)\n* **樹**\n  * [深度優先搜尋](src/algorithms/tree/depth-first-search) (DFS)\n  * [廣度優先搜尋](src/algorithms/tree/breadth-first-search) (BFS)\n* **圖**\n  * [深度優先搜尋](src/algorithms/graph/depth-first-search) (DFS)\n  * [廣度優先搜尋](src/algorithms/graph/breadth-first-search) (BFS)\n  * [Dijkstra 演算法](src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑\n  * [Bellman-Ford 演算法](src/algorithms/graph/bellman-ford) - 找到所有圖頂點的最短路徑\n  * [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions)\n  * [Prim’s 演算法](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n  * [Kruskal’s 演算法](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n  * [拓撲排序](src/algorithms/graph/topological-sorting) - DFS method\n  * [關節點](src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based)\n  * [橋](src/algorithms/graph/bridges) - DFS based algorithm\n  * [尤拉路徑及尤拉環](src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once\n  * [漢彌爾頓環](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once\n  * [強連通組件](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm\n  * [旅行推銷員問題](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city\n  * [Floyd-Warshall algorithm](src/algorithms/graph/floyd-warshall) - 一次循环可以找出所有頂點之间的最短路徑\n* **未分類**\n  * [河內塔](src/algorithms/uncategorized/hanoi-tower)\n  * [N-皇后問題](src/algorithms/uncategorized/n-queens)\n  * [騎士走棋盤](src/algorithms/uncategorized/knight-tour)\n\n### 演算法範型\n\n演算法的範型是一個泛用方法或設計一類底層演算法的方式。它是一個比演算法的概念更高階的抽象化，就像是演算法是比電腦程式更高階的抽象化。\n\n* **暴力法** - 尋遍所有的可能解然後選取最好的解\n  * [最大子序列](src/algorithms/sets/maximum-subarray)\n  * [旅行推銷員問題](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city\n* **貪婪法** - choose the best option at the current time, without any consideration for the future\n  * [未定背包問題](src/algorithms/sets/knapsack-problem)\n  * [Dijkstra 演算法](src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑\n  * [Prim’s 演算法](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n  * [Kruskal’s 演算法](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph\n* **分治法** - divide the problem into smaller parts and then solve those parts\n  * [二元搜尋](src/algorithms/search/binary-search)\n  * [河內塔](src/algorithms/uncategorized/hanoi-tower)\n  * [歐幾里得演算法](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)\n  * [排列](src/algorithms/sets/permutations) (有/無重複)\n  * [组合](src/algorithms/sets/combinations) (有/無重複)\n  * [合併排序](src/algorithms/sorting/merge-sort)\n  * [快速排序](src/algorithms/sorting/quick-sort)\n  * [樹深度優先搜尋](src/algorithms/tree/depth-first-search) (DFS)\n  * [圖深度優先搜尋](src/algorithms/graph/depth-first-search) (DFS)\n* **動態編程** - build up to a solution using previously found sub-solutions\n  * [費伯納西數列](src/algorithms/math/fibonacci)\n  * [萊溫斯坦距離](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences\n  * [最長共同子序列](src/algorithms/sets/longest-common-subsequence) (LCS)\n  * [最長共同子字串](src/algorithms/string/longest-common-substring)\n  * [最長遞增子序列](src/algorithms/sets/longest-increasing-subsequence)\n  * [最短共同子序列](src/algorithms/sets/shortest-common-supersequence)\n  * [0/1背包問題](src/algorithms/sets/knapsack-problem)\n  * [整數拆分](src/algorithms/math/integer-partition)\n  * [最大子序列](src/algorithms/sets/maximum-subarray)\n  * [Bellman-Ford 演算法](src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices\n* **回溯法** - 用類似暴力法來嘗試產生所有可能解，但每次只在能滿足所有測試條件，且只有繼續產生子序列方案來產生的解決方案。否則回溯並尋找不同路徑的解決方案。\n  * [漢彌爾頓迴路](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once\n  * [N-皇后問題](src/algorithms/uncategorized/n-queens)\n  * [騎士走棋盤](src/algorithms/uncategorized/knight-tour)\n* **Branch & Bound**\n\n## 如何使用本知識庫\n\n**安裝所有必須套件**\n\n```\nnpm install\n```\n\n**執行所有測試**\n```\nnpm test\n```\n\n**以名稱執行該測試**\n```\nnpm test -- 'LinkedList'\n```\n**練習場**\n\n你可以透過在`./src/playground/playground.js`裡面的檔案練習資料結構以及演算法，並且撰寫在`./src/playground/__test__/playground.test.js`裡面的測試程式。\n\n接著直接執行下列的指令來測試你練習的 code 是否如預期運作：\n\n```\nnpm test -- 'playground'\n```\n\n## 有用的資訊\n\n### 參考\n\n[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n### 大 O 標記\n\n特別用大 O 標記演算法增長度的排序。\n\n![Big O 表](./assets/big-o-graph.png)\n\n資料來源: [Big O Cheat Sheet](http://bigocheatsheet.com/).\n\n下列列出幾個常用的 Big O 標記以及其不同大小資料量輸入後的運算效能比較。\n\n| Big O 標記     | 10個資料量需花費的時間       | 100個資料量需花費的時間       | 1000個資料量需花費的時間        |\n| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |\n| **O(1)**       | 1                            | 1                             | 1                               |\n| **O(log N)**   | 3                            | 6                             | 9                               |\n| **O(N)**       | 10                           | 100                           | 1000                            |\n| **O(N log N)** | 30                           | 600                           | 9000                            |\n| **O(N^2)**     | 100                          | 10000                         | 1000000                         |\n| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |\n| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |\n\n### 資料結構運作複雜度\n\n| 資料結構                | 存取      | 搜尋      | 插入      | 刪除      |\n| ----------------------- | :-------: | :-------: | :-------: | :-------: |\n| **陣列**                | 1         | n         | n         | n         |\n| **堆疊**                | n         | n         | 1         | 1         |\n| **貯列**                | n         | n         | 1         | 1         |\n| **鏈結串列**            | n         | n         | 1         | 1         |\n| **雜湊表**              | -         | n         | n         | n         |\n| **二元搜尋樹**          | n         | n         | n         | n         |\n| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |\n| **紅黑樹**              | log(n)    | log(n)    | log(n)    | log(n)    |\n| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |\n\n### 陣列排序演算法複雜度\n\n| 名稱                   | 最佳      | 平均      | 最差          | 記憶體    | 穩定      |\n| ---------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: |\n| **氣泡排序**           | n         | n^2       | n^2           | 1         | Yes       |\n| **插入排序**           | n         | n^2       | n^2           | 1         | Yes       |\n| **選擇排序**           | n^2       | n^2       | n^2           | 1         | No        |\n| **Heap 排序**          | n log(n)  | n log(n)  | n log(n)      | 1         | No        |\n| **合併排序**           | n log(n)  | n log(n)  | n log(n)      | n         | Yes       |\n| **快速排序**           | n log(n)  | n log(n)  | n^2           | log(n)    | No        |\n| **希爾排序**           | n log(n)  | 由gap sequence決定   | n (log(n))^2  | 1         | No        |\n\n> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  // The bail config option can be used here to have Jest stop running tests after\n  // the first failure.\n  bail: false,\n\n  // Indicates whether each individual test should be reported during the run.\n  verbose: false,\n\n  // Indicates whether the coverage information should be collected while executing the test\n  collectCoverage: false,\n\n  // The directory where Jest should output its coverage files.\n  coverageDirectory: './coverage/',\n\n  // If the test path matches any of the patterns, it will be skipped.\n  testPathIgnorePatterns: ['<rootDir>/node_modules/'],\n\n  // If the file path matches any of the patterns, coverage information will be skipped.\n  coveragePathIgnorePatterns: ['<rootDir>/node_modules/'],\n\n  // The pattern Jest uses to detect test files.\n  testRegex: '(/__tests__/.*|(\\\\.|/)(test|spec))\\\\.jsx?$',\n\n  // This option sets the URL for the jsdom environment.\n  // It is reflected in properties such as location.href.\n  // @see: https://github.com/facebook/jest/issues/6769\n  testEnvironmentOptions: {\n    url: 'http://localhost/',\n  },\n\n  // @see: https://jestjs.io/docs/en/configuration#coveragethreshold-object\n  coverageThreshold: {\n    global: {\n      statements: 100,\n      branches: 95,\n      functions: 100,\n      lines: 100,\n    },\n  },\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"javascript-algorithms-and-data-structures\",\n  \"version\": \"0.0.4\",\n  \"description\": \"Algorithms and data-structures implemented on JavaScript\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/trekhleb/javascript-algorithms.git\"\n  },\n  \"keywords\": [\n    \"computer-science\",\n    \"cs\",\n    \"algorithms\",\n    \"data-structures\",\n    \"javascript\",\n    \"algorithm\",\n    \"javascript-algorithms\",\n    \"sorting-algorithms\",\n    \"graph\",\n    \"tree\",\n    \"interview\",\n    \"interview-preparation\"\n  ],\n  \"author\": \"Oleksii Trekhleb (https://trekhleb.dev)\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/trekhleb/javascript-algorithms/issues\"\n  },\n  \"homepage\": \"https://github.com/trekhleb/javascript-algorithms#readme\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"lint\": \"eslint ./src/**\",\n    \"test\": \"jest\",\n    \"coverage\": \"npm run test -- --coverage\",\n    \"ci\": \"npm run lint && npm run coverage\",\n    \"prepare\": \"husky\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.28.6\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@types/jest\": \"^30.0.0\",\n    \"eslint\": \"^8.57.1\",\n    \"eslint-config-airbnb\": \"^19.0.4\",\n    \"eslint-plugin-import\": \"^2.32.0\",\n    \"eslint-plugin-jest\": \"^27.9.0\",\n    \"eslint-plugin-jsx-a11y\": \"^6.10.2\",\n    \"husky\": \"^9.1.7\",\n    \"jest\": \"^30.2.0\",\n    \"pngjs\": \"^7.0.0\"\n  },\n  \"engines\": {\n    \"node\": \">=22.0.0\",\n    \"npm\": \">=10.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/algorithms/cryptography/caesar-cipher/README.md",
    "content": "# Caesar Cipher Algorithm\n\n_Read this in other languages:_\n[_Русский_](README.ru-RU.md)\n\nIn 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.\n\n![Caesar Cipher Algorithm](https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg)\n\n## Example\n\nThe 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):\n\n```text\nPlain:    ABCDEFGHIJKLMNOPQRSTUVWXYZ\nCipher:   XYZABCDEFGHIJKLMNOPQRSTUVW\n```\n\nWhen encrypting, a person looks up each letter of the message in the \"plain\" line and writes down the corresponding letter in the \"cipher\" line.\n\n```text\nPlaintext:  THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\nCiphertext: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD\n```\n\n## Complexity\n\n- Time: `O(|n|)`\n- Space: `O(|n|)`\n\n## References\n\n- [Caesar cipher on Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher)\n"
  },
  {
    "path": "src/algorithms/cryptography/caesar-cipher/README.ru-RU.md",
    "content": "# Алгоритм шифра Цезаря\n\nВ криптографии **шифр Цезаря**, также известный как **шифр сдвига**, **код Цезаря** или **сдвиг Цезаря**, является одним из самых простых и широко известных методов шифрования. Это вид шифра подстановки, в котором каждый символ в открытом тексте заменяется символом, находящимся на некотором постоянном числе позиций левее или правее него в алфавите. Например, в шифре со сдвигом вправо на `3`, `D` была бы заменена на `A`, `E` станет `B`, и так далее. Метод назван в честь Юлия Цезаря, который использовал его в своей личной переписке.\n\n![Алгоритм шифра Цезаря](https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg)\n\n## Пример\nЭто преобразование можно представить как выравнивание двух алфавитов; алфавит шифра - это обычный алфавит, повёрнутый влево или вправо на некоторое количество позиций. Например, здесь приведен шифр Цезаря, использующий поворот влево на три позиции, что эквивалентно сдвигу вправо на 23 (параметр сдвига используется в качестве ключа):\n\n```text\nОбычный:    ABCDEFGHIJKLMNOPQRSTUVWXYZ\nШифрованный:   XYZABCDEFGHIJKLMNOPQRSTUVW\n```\n\nПри шифровании человек просматривает каждую букву сообщения в \"открытой\" строке и записывает соответствующую букву в \"шифрованной\" строке.\n\n```text\nОбычный текст:     THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\nШифрованный текст: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD\n```\n\n## Сложность\n\n- Время: `O(|n|)`\n- Пространство: `O(|n|)`\n\n## Ссылки\n\n- [Шифр Цезаря на Wikipedia](https://ru.wikipedia.org/wiki/Шифр_Цезаря)\n"
  },
  {
    "path": "src/algorithms/cryptography/caesar-cipher/__test__/caesarCipher.test.js",
    "content": "import { caesarCipherEncrypt, caesarCipherDecrypt } from '../caesarCipher';\n\ndescribe('caesarCipher', () => {\n  it('should not change a string with zero shift', () => {\n    expect(caesarCipherEncrypt('abcd', 0)).toBe('abcd');\n    expect(caesarCipherDecrypt('abcd', 0)).toBe('abcd');\n  });\n\n  it('should cipher a string with different shifts', () => {\n    expect(caesarCipherEncrypt('abcde', 3)).toBe('defgh');\n    expect(caesarCipherDecrypt('defgh', 3)).toBe('abcde');\n\n    expect(caesarCipherEncrypt('abcde', 1)).toBe('bcdef');\n    expect(caesarCipherDecrypt('bcdef', 1)).toBe('abcde');\n\n    expect(caesarCipherEncrypt('xyz', 1)).toBe('yza');\n    expect(caesarCipherDecrypt('yza', 1)).toBe('xyz');\n  });\n\n  it('should be case insensitive', () => {\n    expect(caesarCipherEncrypt('ABCDE', 3)).toBe('defgh');\n  });\n\n  it('should correctly handle an empty strings', () => {\n    expect(caesarCipherEncrypt('', 3)).toBe('');\n  });\n\n  it('should not cipher unknown chars', () => {\n    expect(caesarCipherEncrypt('ab2cde', 3)).toBe('de2fgh');\n    expect(caesarCipherDecrypt('de2fgh', 3)).toBe('ab2cde');\n  });\n\n  it('should encrypt and decrypt full phrases', () => {\n    expect(caesarCipherEncrypt('THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG', 23))\n      .toBe('qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald');\n\n    expect(caesarCipherDecrypt('qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald', 23))\n      .toBe('the quick brown fox jumps over the lazy dog');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/cryptography/caesar-cipher/caesarCipher.js",
    "content": "// Create alphabet array: ['a', 'b', 'c', ..., 'z'].\nconst englishAlphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');\n\n/**\n * Generates a cipher map out of the alphabet.\n * Example with a shift 3: {'a': 'd', 'b': 'e', 'c': 'f', ...}\n *\n * @param {string[]} alphabet - i.e. ['a', 'b', 'c', ... , 'z']\n * @param {number} shift - i.e. 3\n * @return {Object} - i.e. {'a': 'd', 'b': 'e', 'c': 'f', ..., 'z': 'c'}\n */\nconst getCipherMap = (alphabet, shift) => {\n  return alphabet\n    .reduce((charsMap, currentChar, charIndex) => {\n      const charsMapClone = { ...charsMap };\n      // Making the shift to be cyclic (i.e. with a shift of 1 - 'z' would be mapped to 'a').\n      let encryptedCharIndex = (charIndex + shift) % alphabet.length;\n      // Support negative shifts for creating a map for decryption\n      // (i.e. with shift -1 - 'a' would be mapped to 'z').\n      if (encryptedCharIndex < 0) {\n        encryptedCharIndex += alphabet.length;\n      }\n      charsMapClone[currentChar] = alphabet[encryptedCharIndex];\n      return charsMapClone;\n    }, {});\n};\n\n/**\n * @param {string} str\n * @param {number} shift\n * @param {string[]} alphabet\n * @return {string}\n */\nexport const caesarCipherEncrypt = (str, shift, alphabet = englishAlphabet) => {\n  // Create a cipher map:\n  const cipherMap = getCipherMap(alphabet, shift);\n  return str\n    .toLowerCase()\n    .split('')\n    .map((char) => cipherMap[char] || char)\n    .join('');\n};\n\n/**\n * @param {string} str\n * @param {number} shift\n * @param {string[]} alphabet\n * @return {string}\n */\nexport const caesarCipherDecrypt = (str, shift, alphabet = englishAlphabet) => {\n  // Create a cipher map:\n  const cipherMap = getCipherMap(alphabet, -shift);\n  return str\n    .toLowerCase()\n    .split('')\n    .map((char) => cipherMap[char] || char)\n    .join('');\n};\n"
  },
  {
    "path": "src/algorithms/cryptography/hill-cipher/README.md",
    "content": "# Hill Cipher\n\nThe **Hill cipher** is a [polygraphic substitution](https://en.wikipedia.org/wiki/Polygraphic_substitution) cipher based on linear algebra.\n\nEach 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:\n\n| **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 |\n| ------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n| **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 |\n\n## Encryption\n\nTo 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`.\n\nThe 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`.\n\nConsider the message `ACT`, and the key below (or `GYB/NQK/URP` in letters):\n\n```\n| 6   24   1  |\n| 13  16   10 |\n| 20  17   15 |\n```\n\nSince `A` is`0`, `C` is `2` and `T` is `19`, the message is the vector:\n\n```\n|  0  |\n|  2  |\n|  19 |\n```\n\nThus, the enciphered vector is given by:\n\n```\n| 6   24   1  |  |  0  |   |  67  |   |  15 |\n| 13  16   10 |  |  2  | = |  222 | ≡ |  14 | (mod 26)\n| 20  17   15 |  |  19 |   |  319 |   |  7  |\n```\n\nwhich corresponds to a ciphertext of `POH`.\n\nNow, suppose that our message is instead `CAT` (notice how we're using the same letters as in `ACT` here), or:\n\n```\n|  2  |\n|  0  |\n|  19 |\n```\n\nThis time, the enciphered vector is given by:\n\n```\n| 6   24   1  |  |  2  |   |  31  |   |  5  |\n| 13  16   10 |  |  0  | = |  216 | ≡ |  8  | (mod 26)\n| 20  17   15 |  |  19 |   |  325 |   |  13 |\n```\n\nwhich corresponds to a ciphertext of `FIN`. Every letter has changed.\n\n## Decryption\n\nTo 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:\n\n```\n                -1\n| 6   24   1  |                | 8   5    10 |\n| 13  16   10 |    (mod 26) ≡  | 21  8    21 |\n| 20  17   15 |                | 21  12   8  |\n```\n\nTaking the previous example ciphertext of `POH`, we get:\n\n```\n| 8   5    10 |  |  15 |   |  260 |   |  0  |\n| 21  8    21 |  |  14 | = |  574 | ≡ |  2  | (mod 26)\n| 21  12   8  |  |  7  |   |  539 |   |  19 |\n```\n\nwhich gets us back to `ACT`, as expected.\n\n## Defining the encrypting matrix\n\nTwo complications exist in picking the encrypting matrix:\n\n1. 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.\n2. The determinant of the encrypting matrix must not have any common factors with the modular base.\n\nThus, 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.\n\n## References\n\n- [Hill cipher on Wikipedia](https://en.wikipedia.org/wiki/Hill_cipher)\n- [Matrix inversion on MathIsFun](https://www.mathsisfun.com/algebra/matrix-inverse.html)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/hill-cipher/)\n\n"
  },
  {
    "path": "src/algorithms/cryptography/hill-cipher/_test_/hillCipher.test.js",
    "content": "import { hillCipherEncrypt, hillCipherDecrypt } from '../hillCipher';\n\ndescribe('hillCipher', () => {\n  it('should throw an exception when trying to decipher', () => {\n    expect(hillCipherDecrypt).toThrow('This method is not implemented yet');\n  });\n\n  it('should throw an error when message or keyString contains none letter character', () => {\n    const invalidCharacterInMessage = () => {\n      hillCipherEncrypt('hell3', 'helloworld');\n    };\n    const invalidCharacterInKeyString = () => {\n      hillCipherEncrypt('hello', 'hel12world');\n    };\n    expect(invalidCharacterInMessage).toThrow(\n      'The message and key string can only contain letters',\n    );\n    expect(invalidCharacterInKeyString).toThrow(\n      'The message and key string can only contain letters',\n    );\n  });\n\n  it('should throw an error when the length of the keyString has a square root which is not integer', () => {\n    const invalidLengthOfKeyString = () => {\n      hillCipherEncrypt('ab', 'ab');\n    };\n    expect(invalidLengthOfKeyString).toThrow(\n      'Invalid key string length. The square root of the key string must be an integer',\n    );\n  });\n\n  it('should throw an error when the length of the keyString does not equal to the power of length of the message', () => {\n    const invalidLengthOfKeyString = () => {\n      hillCipherEncrypt('ab', 'aaabbbccc');\n    };\n    expect(invalidLengthOfKeyString).toThrow(\n      'Invalid key string length. The key length must be a square of message length',\n    );\n  });\n\n  it('should encrypt passed message using Hill Cipher', () => {\n    expect(hillCipherEncrypt('ACT', 'GYBNQKURP')).toBe('POH');\n    expect(hillCipherEncrypt('CAT', 'GYBNQKURP')).toBe('FIN');\n    expect(hillCipherEncrypt('GFG', 'HILLMAGIC')).toBe('SWK');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/cryptography/hill-cipher/hillCipher.js",
    "content": "import * as mtrx from '../../math/matrix/Matrix';\n\n// The code of an 'A' character (equals to 65).\nconst alphabetCodeShift = 'A'.codePointAt(0);\nconst englishAlphabetSize = 26;\n\n/**\n * Generates key matrix from given keyString.\n *\n * @param {string} keyString - a string to build a key matrix (must be of matrixSize^2 length).\n * @return {number[][]} keyMatrix\n */\nconst generateKeyMatrix = (keyString) => {\n  const matrixSize = Math.sqrt(keyString.length);\n  if (!Number.isInteger(matrixSize)) {\n    throw new Error(\n      'Invalid key string length. The square root of the key string must be an integer',\n    );\n  }\n  let keyStringIndex = 0;\n  return mtrx.generate(\n    [matrixSize, matrixSize],\n    // Callback to get a value of each matrix cell.\n    // The order the matrix is being filled in is from left to right, from top to bottom.\n    () => {\n      // A → 0, B → 1, ..., a → 32, b → 33, ...\n      const charCodeShifted = (keyString.codePointAt(keyStringIndex)) % alphabetCodeShift;\n      keyStringIndex += 1;\n      return charCodeShifted;\n    },\n  );\n};\n\n/**\n * Generates a message vector from a given message.\n *\n * @param {string} message - the message to encrypt.\n * @return {number[][]} messageVector\n */\nconst generateMessageVector = (message) => {\n  return mtrx.generate(\n    [message.length, 1],\n    // Callback to get a value of each matrix cell.\n    // The order the matrix is being filled in is from left to right, from top to bottom.\n    (cellIndices) => {\n      const rowIndex = cellIndices[0];\n      return message.codePointAt(rowIndex) % alphabetCodeShift;\n    },\n  );\n};\n\n/**\n * Encrypts the given message using Hill Cipher.\n *\n * @param {string} message plaintext\n * @param {string} keyString\n * @return {string} cipherString\n */\nexport function hillCipherEncrypt(message, keyString) {\n  // The keyString and message can only contain letters.\n  const onlyLettersRegExp = /^[a-zA-Z]+$/;\n  if (!onlyLettersRegExp.test(message) || !onlyLettersRegExp.test(keyString)) {\n    throw new Error('The message and key string can only contain letters');\n  }\n\n  const keyMatrix = generateKeyMatrix(keyString);\n  const messageVector = generateMessageVector(message);\n\n  // keyString.length must equal to square of message.length\n  if (keyMatrix.length !== message.length) {\n    throw new Error('Invalid key string length. The key length must be a square of message length');\n  }\n\n  const cipherVector = mtrx.dot(keyMatrix, messageVector);\n  let cipherString = '';\n  for (let row = 0; row < cipherVector.length; row += 1) {\n    const item = cipherVector[row];\n    cipherString += String.fromCharCode((item % englishAlphabetSize) + alphabetCodeShift);\n  }\n\n  return cipherString;\n}\n\n// @TODO: Implement this method.\nexport const hillCipherDecrypt = () => {\n  throw new Error('This method is not implemented yet');\n};\n"
  },
  {
    "path": "src/algorithms/cryptography/polynomial-hash/PolynomialHash.js",
    "content": "const DEFAULT_BASE = 37;\nconst DEFAULT_MODULUS = 101;\n\nexport default class PolynomialHash {\n  /**\n   * @param {number} [base] - Base number that is used to create the polynomial.\n   * @param {number} [modulus] - Modulus number that keeps the hash from overflowing.\n   */\n  constructor({ base = DEFAULT_BASE, modulus = DEFAULT_MODULUS } = {}) {\n    this.base = base;\n    this.modulus = modulus;\n  }\n\n  /**\n   * Function that creates hash representation of the word.\n   *\n   * Time complexity: O(word.length).\n   *\n   * @param {string} word - String that needs to be hashed.\n   * @return {number}\n   */\n  hash(word) {\n    const charCodes = Array.from(word).map((char) => this.charToNumber(char));\n\n    let hash = 0;\n    for (let charIndex = 0; charIndex < charCodes.length; charIndex += 1) {\n      hash *= this.base;\n      hash += charCodes[charIndex];\n      hash %= this.modulus;\n    }\n\n    return hash;\n  }\n\n  /**\n   * Function that creates hash representation of the word\n   * based on previous word (shifted by one character left) hash value.\n   *\n   * Recalculates the hash representation of a word so that it isn't\n   * necessary to traverse the whole word again.\n   *\n   * Time complexity: O(1).\n   *\n   * @param {number} prevHash\n   * @param {string} prevWord\n   * @param {string} newWord\n   * @return {number}\n   */\n  roll(prevHash, prevWord, newWord) {\n    let hash = prevHash;\n\n    const prevValue = this.charToNumber(prevWord[0]);\n    const newValue = this.charToNumber(newWord[newWord.length - 1]);\n\n    let prevValueMultiplier = 1;\n    for (let i = 1; i < prevWord.length; i += 1) {\n      prevValueMultiplier *= this.base;\n      prevValueMultiplier %= this.modulus;\n    }\n\n    hash += this.modulus;\n    hash -= (prevValue * prevValueMultiplier) % this.modulus;\n\n    hash *= this.base;\n    hash += newValue;\n    hash %= this.modulus;\n\n    return hash;\n  }\n\n  /**\n   * Converts char to number.\n   *\n   * @param {string} char\n   * @return {number}\n   */\n  charToNumber(char) {\n    let charCode = char.codePointAt(0);\n\n    // Check if character has surrogate pair.\n    const surrogate = char.codePointAt(1);\n    if (surrogate !== undefined) {\n      const surrogateShift = 2 ** 16;\n      charCode += surrogate * surrogateShift;\n    }\n\n    return charCode;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/cryptography/polynomial-hash/README.md",
    "content": "# Polynomial Rolling Hash\n\n## Hash Function\n\n**Hash functions** are used to map large data sets of elements of an arbitrary \nlength (*the keys*) to smaller data sets of elements of a fixed length\n(*the fingerprints*).\n\nThe basic application of hashing is efficient testing of equality of keys by\ncomparing their fingerprints.\n\nA *collision* happens when two different keys have the same fingerprint. The way \nin which collisions are handled is crucial in most applications of hashing. \nHashing is particularly useful in construction of efficient practical algorithms.\n\n## Rolling Hash\n\nA **rolling hash** (also known as recursive hashing or rolling checksum) is a hash\nfunction where the input is hashed in a window that moves through the input.\n\nA few hash functions allow a rolling hash to be computed very quickly — the new \nhash value is rapidly calculated given only the following data:\n\n- old hash value,\n- the old value removed from the window,\n- and the new value added to the window.\n\n## Polynomial String Hashing\n\nAn ideal hash function for strings should obviously depend both on the *multiset* of\nthe symbols present in the key and on the *order* of the symbols. The most common \nfamily of such hash functions treats the symbols of a string as coefficients of \na *polynomial* with an integer variable `p` and computes its value modulo an \ninteger constant `M`:\n\nThe *Rabin–Karp string search algorithm* is often explained using a very simple\nrolling hash function that only uses multiplications and \nadditions - **polynomial rolling hash**:\n\n> 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>\n\nwhere `p` is a constant, and *(s<sub>1</sub>, ... , s<sub>k</sub>)* are the input\ncharacters.\n\nFor example we can convert short strings to key numbers by multiplying digit codes by \npowers of a constant. The three letter word `ace` could turn into a number \nby calculating:\n\n> key = 1 * 26<sup>2</sup> + 3 * 26<sup>1</sup> + 5 * 26<sup>0</sup>\n\nIn order to avoid manipulating huge `H` values, all math is done modulo `M`.\n\n> 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\n\nA careful choice of the parameters `M`, `p` is important to obtain “good”\nproperties of the hash function, i.e., low collision rate.\n\nThis approach has the desirable attribute of involving all the characters in the \ninput string. The calculated key value can then be hashed into an array index in\nthe usual way:\n\n```javascript\nfunction hash(key, arraySize) {\n  const base = 13;\n\n  let hash = 0;\n  for (let charIndex = 0; charIndex < key.length; charIndex += 1) {\n    const charCode = key.charCodeAt(charIndex);\n    hash += charCode * (base ** (key.length - charIndex - 1));\n  }\n\n  return hash % arraySize;\n}\n```\n\nThe `hash()` method is not as efficient as it might be. Other than the \ncharacter conversion, there are two multiplications and an addition inside \nthe loop. We can eliminate one multiplication by using **Horner's method*:\n \n> 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>\n\nIn other words:\n\n> H<sub>i</sub> = (P * H<sub>i-1</sub> + S<sub>i</sub>) mod M\n\nThe `hash()` cannot handle long strings because the hashVal exceeds the size of \nint. Notice that the key always ends up being less than the array size. \nIn Horner's method we can apply the modulo (%) operator at each step in the \ncalculation. This gives the same result as applying the modulo operator once at \nthe end, but avoids the overflow.\n\n```javascript\nfunction hash(key, arraySize) {\n  const base = 13;\n\n  let hash = 0;\n  for (let charIndex = 0; charIndex < key.length; charIndex += 1) {\n    const charCode = key.charCodeAt(charIndex);\n    hash = (hash * base + charCode) % arraySize;\n  }\n\n  return hash;\n}\n```\n\nPolynomial hashing has a rolling property: the fingerprints can be updated \nefficiently when symbols are added or removed at the ends of the string\n(provided that an array of powers of p modulo M of sufficient length is stored).\nThe popular Rabin–Karp pattern matching algorithm is based on this property\n\n## References\n\n- [Where to Use Polynomial String Hashing](https://www.mii.lt/olympiads_in_informatics/pdf/INFOL119.pdf)\n- [Hashing on uTexas](https://www.cs.utexas.edu/~mitra/csSpring2017/cs313/lectures/hash.html)\n- [Hash Function on Wikipedia](https://en.wikipedia.org/wiki/Hash_function)\n- [Rolling Hash on Wikipedia](https://en.wikipedia.org/wiki/Rolling_hash)\n"
  },
  {
    "path": "src/algorithms/cryptography/polynomial-hash/SimplePolynomialHash.js",
    "content": "const DEFAULT_BASE = 17;\n\nexport default class SimplePolynomialHash {\n  /**\n   * @param {number} [base] - Base number that is used to create the polynomial.\n   */\n  constructor(base = DEFAULT_BASE) {\n    this.base = base;\n  }\n\n  /**\n   * Function that creates hash representation of the word.\n   *\n   * Time complexity: O(word.length).\n   *\n   * @assumption: This version of the function  doesn't use modulo operator.\n   * Thus it may produce number overflows by generating numbers that are\n   * bigger than Number.MAX_SAFE_INTEGER. This function is mentioned here\n   * for simplicity and LEARNING reasons.\n   *\n   * @param {string} word - String that needs to be hashed.\n   * @return {number}\n   */\n  hash(word) {\n    let hash = 0;\n    for (let charIndex = 0; charIndex < word.length; charIndex += 1) {\n      hash += word.charCodeAt(charIndex) * (this.base ** charIndex);\n    }\n\n    return hash;\n  }\n\n  /**\n   * Function that creates hash representation of the word\n   * based on previous word (shifted by one character left) hash value.\n   *\n   * Recalculates the hash representation of a word so that it isn't\n   * necessary to traverse the whole word again.\n   *\n   * Time complexity: O(1).\n   *\n   * @assumption: This function doesn't use modulo operator and thus is not safe since\n   * it may deal with numbers that are bigger than Number.MAX_SAFE_INTEGER. This\n   * function is mentioned here for simplicity and LEARNING reasons.\n   *\n   * @param {number} prevHash\n   * @param {string} prevWord\n   * @param {string} newWord\n   * @return {number}\n   */\n  roll(prevHash, prevWord, newWord) {\n    let hash = prevHash;\n\n    const prevValue = prevWord.charCodeAt(0);\n    const newValue = newWord.charCodeAt(newWord.length - 1);\n\n    hash -= prevValue;\n    hash /= this.base;\n    hash += newValue * (this.base ** (newWord.length - 1));\n\n    return hash;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/cryptography/polynomial-hash/__test__/PolynomialHash.test.js",
    "content": "import PolynomialHash from '../PolynomialHash';\n\ndescribe('PolynomialHash', () => {\n  it('should calculate new hash based on previous one', () => {\n    const bases = [3, 79, 101, 3251, 13229, 122743, 3583213];\n    const mods = [79, 101];\n    const frameSizes = [5, 20];\n\n    // @TODO: Provide Unicode support.\n    const text = 'Lorem Ipsum is simply dummy text of the printing and '\n      + 'typesetting industry. Lorem Ipsum has been the industry\\'s standard '\n      + 'galley of type and \\u{ffff} scrambled it to make a type specimen book. It '\n      + 'electronic 耀 typesetting, remaining essentially unchanged. It was '\n      // + 'popularised in the \\u{20005} \\u{20000}1960s with the release of Letraset sheets '\n      + 'publishing software like Aldus PageMaker 耀 including versions of Lorem.';\n\n    // Check hashing for different prime base.\n    bases.forEach((base) => {\n      mods.forEach((modulus) => {\n        const polynomialHash = new PolynomialHash({ base, modulus });\n\n        // Check hashing for different word lengths.\n        frameSizes.forEach((frameSize) => {\n          let previousWord = text.substr(0, frameSize);\n          let previousHash = polynomialHash.hash(previousWord);\n\n          // Shift frame through the whole text.\n          for (let frameShift = 1; frameShift < (text.length - frameSize); frameShift += 1) {\n            const currentWord = text.substr(frameShift, frameSize);\n            const currentHash = polynomialHash.hash(currentWord);\n            const currentRollingHash = polynomialHash.roll(previousHash, previousWord, currentWord);\n\n            // Check that rolling hash is the same as directly calculated hash.\n            expect(currentRollingHash).toBe(currentHash);\n\n            previousWord = currentWord;\n            previousHash = currentHash;\n          }\n        });\n      });\n    });\n  });\n\n  it('should generate numeric hashed less than 100', () => {\n    const polynomialHash = new PolynomialHash({ modulus: 100 });\n\n    expect(polynomialHash.hash('Some long text that is used as a key')).toBe(41);\n    expect(polynomialHash.hash('Test')).toBe(92);\n    expect(polynomialHash.hash('a')).toBe(97);\n    expect(polynomialHash.hash('b')).toBe(98);\n    expect(polynomialHash.hash('c')).toBe(99);\n    expect(polynomialHash.hash('d')).toBe(0);\n    expect(polynomialHash.hash('e')).toBe(1);\n    expect(polynomialHash.hash('ab')).toBe(87);\n\n    // @TODO: Provide Unicode support.\n    expect(polynomialHash.hash('\\u{20000}')).toBe(92);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/cryptography/polynomial-hash/__test__/SimplePolynomialHash.test.js",
    "content": "import SimplePolynomialHash from '../SimplePolynomialHash';\n\ndescribe('PolynomialHash', () => {\n  it('should calculate new hash based on previous one', () => {\n    const bases = [3, 5];\n    const frameSizes = [5, 10];\n\n    const text = 'Lorem Ipsum is simply dummy text of the printing and '\n      + 'typesetting industry. Lorem Ipsum has been the industry\\'s standard '\n      + 'galley of type and \\u{ffff} scrambled it to make a type specimen book. It '\n      + 'electronic 耀 typesetting, remaining essentially unchanged. It was '\n      + 'popularised in the 1960s with the release of Letraset sheets '\n      + 'publishing software like Aldus 耀 PageMaker including versions of Lorem.';\n\n    // Check hashing for different prime base.\n    bases.forEach((base) => {\n      const polynomialHash = new SimplePolynomialHash(base);\n\n      // Check hashing for different word lengths.\n      frameSizes.forEach((frameSize) => {\n        let previousWord = text.substr(0, frameSize);\n        let previousHash = polynomialHash.hash(previousWord);\n\n        // Shift frame through the whole text.\n        for (let frameShift = 1; frameShift < (text.length - frameSize); frameShift += 1) {\n          const currentWord = text.substr(frameShift, frameSize);\n          const currentHash = polynomialHash.hash(currentWord);\n          const currentRollingHash = polynomialHash.roll(previousHash, previousWord, currentWord);\n\n          // Check that rolling hash is the same as directly calculated hash.\n          expect(currentRollingHash).toBe(currentHash);\n\n          previousWord = currentWord;\n          previousHash = currentHash;\n        }\n      });\n    });\n  });\n\n  it('should generate numeric hashed', () => {\n    const polynomialHash = new SimplePolynomialHash();\n\n    expect(polynomialHash.hash('Test')).toBe(604944);\n    expect(polynomialHash.hash('a')).toBe(97);\n    expect(polynomialHash.hash('b')).toBe(98);\n    expect(polynomialHash.hash('c')).toBe(99);\n    expect(polynomialHash.hash('d')).toBe(100);\n    expect(polynomialHash.hash('e')).toBe(101);\n    expect(polynomialHash.hash('ab')).toBe(1763);\n    expect(polynomialHash.hash('abc')).toBe(30374);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/cryptography/rail-fence-cipher/README.md",
    "content": "# Rail Fence Cipher\n\nThe **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.\n\nFrom [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:\n\n```\nW . . . E . . . C . . . R . . . L . . . T . . . E\n. E . R . D . S . O . E . E . F . E . A . O . C .\n. . A . . . I . . . V . . . D . . . E . . . N . .\n-------------------------------------------------\n             WECRLTEERDSOEEFEAOCAIVDEN\n```\n\nThe 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.\n\n```\nW . . . E . . . C . . . R . . . L . . . T . . . E\n. - . - . - . - . - . - . - . - . - . - . - . - .\n. . - . . . - . . . - . . . - . . . - . . . - . .\n```\n\nIt'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\n## References\n\n- [Rail Fence Cipher on Wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher)\n- [Rail Fence Cipher Calculator](https://crypto.interactive-maths.com/rail-fence-cipher.html)\n"
  },
  {
    "path": "src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCipher.test.js",
    "content": "import { encodeRailFenceCipher, decodeRailFenceCipher } from '../railFenceCipher';\n\ndescribe('railFenceCipher', () => {\n  it('encodes a string correctly for base=3', () => {\n    expect(encodeRailFenceCipher('', 3)).toBe('');\n    expect(encodeRailFenceCipher('12345', 3)).toBe(\n      '15243',\n    );\n    expect(encodeRailFenceCipher('WEAREDISCOVEREDFLEEATONCE', 3)).toBe(\n      'WECRLTEERDSOEEFEAOCAIVDEN',\n    );\n    expect(encodeRailFenceCipher('Hello, World!', 3)).toBe(\n      'Hoo!el,Wrdl l',\n    );\n  });\n\n  it('decodes a string correctly for base=3', () => {\n    expect(decodeRailFenceCipher('', 3)).toBe('');\n    expect(decodeRailFenceCipher('WECRLTEERDSOEEFEAOCAIVDEN', 3)).toBe(\n      'WEAREDISCOVEREDFLEEATONCE',\n    );\n    expect(decodeRailFenceCipher('Hoo!el,Wrdl l', 3)).toBe(\n      'Hello, World!',\n    );\n    expect(decodeRailFenceCipher('15243', 3)).toBe(\n      '12345',\n    );\n  });\n\n  it('encodes a string correctly for base=4', () => {\n    expect(encodeRailFenceCipher('', 4)).toBe('');\n    expect(encodeRailFenceCipher('THEYAREATTACKINGFROMTHENORTH', 4)).toBe(\n      'TEKOOHRACIRMNREATANFTETYTGHH',\n    );\n  });\n\n  it('decodes a string correctly for base=4', () => {\n    expect(decodeRailFenceCipher('', 4)).toBe('');\n    expect(decodeRailFenceCipher('TEKOOHRACIRMNREATANFTETYTGHH', 4)).toBe(\n      'THEYAREATTACKINGFROMTHENORTH',\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js",
    "content": "/**\n * @typedef {string[]} Rail\n * @typedef {Rail[]} Fence\n * @typedef {number} Direction\n */\n\n/**\n * @constant DIRECTIONS\n * @type {object}\n * @property {Direction} UP\n * @property {Direction} DOWN\n */\nconst DIRECTIONS = { UP: -1, DOWN: 1 };\n\n/**\n * Builds a fence with a specific number of rows.\n *\n * @param {number} rowsNum\n * @returns {Fence}\n */\nconst buildFence = (rowsNum) => Array(rowsNum)\n  .fill(null)\n  .map(() => []);\n\n/**\n * Get next direction to move (based on the current one) while traversing the fence.\n *\n * @param {object} params\n * @param {number} params.railCount - Number of rows in the fence\n * @param {number} params.currentRail - Current row that we're visiting\n * @param {Direction} params.direction - Current direction\n * @returns {Direction} - The next direction to take\n */\nconst getNextDirection = ({ railCount, currentRail, direction }) => {\n  switch (currentRail) {\n    case 0:\n      // Go down if we're on top of the fence.\n      return DIRECTIONS.DOWN;\n    case railCount - 1:\n      // Go up if we're at the bottom of the fence.\n      return DIRECTIONS.UP;\n    default:\n      // Continue with the same direction if we're in the middle of the fence.\n      return direction;\n  }\n};\n\n/**\n * @param {number} targetRailIndex\n * @param {string} letter\n * @returns {Function}\n */\nconst addCharToRail = (targetRailIndex, letter) => {\n  /**\n   * Given a rail, adds a char to it if it matches a targetIndex.\n   *\n   * @param {Rail} rail\n   * @param {number} currentRail\n   * @returns {Rail}\n   */\n  function onEachRail(rail, currentRail) {\n    return currentRail === targetRailIndex\n      ? [...rail, letter]\n      : rail;\n  }\n  return onEachRail;\n};\n\n/**\n * Hangs the characters on the fence.\n *\n * @param {object} params\n * @param {Fence} params.fence\n * @param {number} params.currentRail\n * @param {Direction} params.direction\n * @param {string[]} params.chars\n * @returns {Fence}\n */\nconst fillEncodeFence = ({\n  fence,\n  currentRail,\n  direction,\n  chars,\n}) => {\n  if (chars.length === 0) {\n    // All chars have been placed on a fence.\n    return fence;\n  }\n\n  const railCount = fence.length;\n\n  // Getting the next character to place on a fence.\n  const [letter, ...nextChars] = chars;\n  const nextDirection = getNextDirection({\n    railCount,\n    currentRail,\n    direction,\n  });\n\n  return fillEncodeFence({\n    fence: fence.map(addCharToRail(currentRail, letter)),\n    currentRail: currentRail + nextDirection,\n    direction: nextDirection,\n    chars: nextChars,\n  });\n};\n\n/**\n * @param {object} params\n * @param {number} params.strLen\n * @param {string[]} params.chars\n * @param {Fence} params.fence\n * @param {number} params.targetRail\n * @param {Direction} params.direction\n * @param {number[]} params.coords\n * @returns {Fence}\n */\nconst fillDecodeFence = (params) => {\n  const {\n    strLen, chars, fence, targetRail, direction, coords,\n  } = params;\n\n  const railCount = fence.length;\n\n  if (chars.length === 0) {\n    return fence;\n  }\n\n  const [currentRail, currentColumn] = coords;\n  const shouldGoNextRail = currentColumn === strLen - 1;\n  const nextDirection = shouldGoNextRail\n    ? DIRECTIONS.DOWN\n    : getNextDirection(\n      { railCount, currentRail, direction },\n    );\n  const nextRail = shouldGoNextRail ? targetRail + 1 : targetRail;\n  const nextCoords = [\n    shouldGoNextRail ? 0 : currentRail + nextDirection,\n    shouldGoNextRail ? 0 : currentColumn + 1,\n  ];\n\n  const shouldAddChar = currentRail === targetRail;\n  const [currentChar, ...remainderChars] = chars;\n  const nextString = shouldAddChar ? remainderChars : chars;\n  const nextFence = shouldAddChar ? fence.map(addCharToRail(currentRail, currentChar)) : fence;\n\n  return fillDecodeFence({\n    strLen,\n    chars: nextString,\n    fence: nextFence,\n    targetRail: nextRail,\n    direction: nextDirection,\n    coords: nextCoords,\n  });\n};\n\n/**\n * @param {object} params\n * @param {number} params.strLen\n * @param {Fence} params.fence\n * @param {number} params.currentRail\n * @param {Direction} params.direction\n * @param {number[]} params.code\n * @returns {string}\n */\nconst decodeFence = (params) => {\n  const {\n    strLen,\n    fence,\n    currentRail,\n    direction,\n    code,\n  } = params;\n\n  if (code.length === strLen) {\n    return code.join('');\n  }\n\n  const railCount = fence.length;\n\n  const [currentChar, ...nextRail] = fence[currentRail];\n  const nextDirection = getNextDirection(\n    { railCount, currentRail, direction },\n  );\n\n  return decodeFence({\n    railCount,\n    strLen,\n    currentRail: currentRail + nextDirection,\n    direction: nextDirection,\n    code: [...code, currentChar],\n    fence: fence.map((rail, idx) => (idx === currentRail ? nextRail : rail)),\n  });\n};\n\n/**\n * Encodes the message using Rail Fence Cipher.\n *\n * @param {string} string - The string to be encoded\n * @param {number} railCount - The number of rails in a fence\n * @returns {string} - Encoded string\n */\nexport const encodeRailFenceCipher = (string, railCount) => {\n  const fence = buildFence(railCount);\n\n  const filledFence = fillEncodeFence({\n    fence,\n    currentRail: 0,\n    direction: DIRECTIONS.DOWN,\n    chars: string.split(''),\n  });\n\n  return filledFence.flat().join('');\n};\n\n/**\n * Decodes the message using Rail Fence Cipher.\n *\n * @param {string} string - Encoded string\n * @param {number} railCount - The number of rows in a fence\n * @returns {string} - Decoded string.\n */\nexport const decodeRailFenceCipher = (string, railCount) => {\n  const strLen = string.length;\n  const emptyFence = buildFence(railCount);\n  const filledFence = fillDecodeFence({\n    strLen,\n    chars: string.split(''),\n    fence: emptyFence,\n    targetRail: 0,\n    direction: DIRECTIONS.DOWN,\n    coords: [0, 0],\n  });\n\n  return decodeFence({\n    strLen,\n    fence: filledFence,\n    currentRail: 0,\n    direction: DIRECTIONS.DOWN,\n    code: [],\n  });\n};\n"
  },
  {
    "path": "src/algorithms/graph/articulation-points/README.md",
    "content": "# Articulation Points (or Cut Vertices)\n\nA vertex in an undirected connected graph is an articulation point\n(or cut vertex) if removing it (and edges through it) disconnects \nthe graph. Articulation points represent vulnerabilities in a \nconnected network – single points whose failure would split the \nnetwork into 2 or more disconnected components. They are useful for \ndesigning reliable networks.\n\nFor a disconnected undirected graph, an articulation point is a \nvertex removing which increases number of connected components.\n\n![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints.png)\n\n![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints1.png)\n\n![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints21.png)\n\n## References\n\n- [GeeksForGeeks](https://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/)\n- [YouTube](https://www.youtube.com/watch?v=2kREIkF9UAs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/articulation-points/__test__/articulationPoints.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport articulationPoints from '../articulationPoints';\n\ndescribe('articulationPoints', () => {\n  it('should find articulation points in simple graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD);\n\n    const articulationPointsSet = Object.values(articulationPoints(graph));\n\n    expect(articulationPointsSet.length).toBe(2);\n    expect(articulationPointsSet[0].getKey()).toBe(vertexC.getKey());\n    expect(articulationPointsSet[1].getKey()).toBe(vertexB.getKey());\n  });\n\n  it('should find articulation points in simple graph with back edge', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD);\n\n    const articulationPointsSet = Object.values(articulationPoints(graph));\n\n    expect(articulationPointsSet.length).toBe(1);\n    expect(articulationPointsSet[0].getKey()).toBe(vertexC.getKey());\n  });\n\n  it('should find articulation points in simple graph with back edge #2', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeCE = new GraphEdge(vertexC, vertexE);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAE)\n      .addEdge(edgeCE)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD);\n\n    const articulationPointsSet = Object.values(articulationPoints(graph));\n\n    expect(articulationPointsSet.length).toBe(1);\n    expect(articulationPointsSet[0].getKey()).toBe(vertexC.getKey());\n  });\n\n  it('should find articulation points in graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n    const edgeEG = new GraphEdge(vertexE, vertexG);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeGF = new GraphEdge(vertexG, vertexF);\n    const edgeFH = new GraphEdge(vertexF, vertexH);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeAC)\n      .addEdge(edgeCD)\n      .addEdge(edgeDE)\n      .addEdge(edgeEG)\n      .addEdge(edgeEF)\n      .addEdge(edgeGF)\n      .addEdge(edgeFH);\n\n    const articulationPointsSet = Object.values(articulationPoints(graph));\n\n    expect(articulationPointsSet.length).toBe(4);\n    expect(articulationPointsSet[0].getKey()).toBe(vertexF.getKey());\n    expect(articulationPointsSet[1].getKey()).toBe(vertexE.getKey());\n    expect(articulationPointsSet[2].getKey()).toBe(vertexD.getKey());\n    expect(articulationPointsSet[3].getKey()).toBe(vertexC.getKey());\n  });\n\n  it('should find articulation points in graph starting with articulation root vertex', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n    const edgeEG = new GraphEdge(vertexE, vertexG);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeGF = new GraphEdge(vertexG, vertexF);\n    const edgeFH = new GraphEdge(vertexF, vertexH);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeDE)\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeAC)\n      .addEdge(edgeCD)\n      .addEdge(edgeEG)\n      .addEdge(edgeEF)\n      .addEdge(edgeGF)\n      .addEdge(edgeFH);\n\n    const articulationPointsSet = Object.values(articulationPoints(graph));\n\n    expect(articulationPointsSet.length).toBe(4);\n    expect(articulationPointsSet[0].getKey()).toBe(vertexF.getKey());\n    expect(articulationPointsSet[1].getKey()).toBe(vertexE.getKey());\n    expect(articulationPointsSet[2].getKey()).toBe(vertexC.getKey());\n    expect(articulationPointsSet[3].getKey()).toBe(vertexD.getKey());\n  });\n\n  it('should find articulation points in yet another graph #1', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeDE);\n\n    const articulationPointsSet = Object.values(articulationPoints(graph));\n\n    expect(articulationPointsSet.length).toBe(2);\n    expect(articulationPointsSet[0].getKey()).toBe(vertexD.getKey());\n    expect(articulationPointsSet[1].getKey()).toBe(vertexC.getKey());\n  });\n\n  it('should find articulation points in yet another graph #2', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeCE = new GraphEdge(vertexC, vertexE);\n    const edgeCF = new GraphEdge(vertexC, vertexF);\n    const edgeEG = new GraphEdge(vertexE, vertexG);\n    const edgeFG = new GraphEdge(vertexF, vertexG);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeCE)\n      .addEdge(edgeCF)\n      .addEdge(edgeEG)\n      .addEdge(edgeFG);\n\n    const articulationPointsSet = Object.values(articulationPoints(graph));\n\n    expect(articulationPointsSet.length).toBe(1);\n    expect(articulationPointsSet[0].getKey()).toBe(vertexC.getKey());\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/articulation-points/articulationPoints.js",
    "content": "import depthFirstSearch from '../depth-first-search/depthFirstSearch';\n\n/**\n * Helper class for visited vertex metadata.\n */\nclass VisitMetadata {\n  constructor({ discoveryTime, lowDiscoveryTime }) {\n    this.discoveryTime = discoveryTime;\n    this.lowDiscoveryTime = lowDiscoveryTime;\n    // We need this in order to check graph root node, whether it has two\n    // disconnected children or not.\n    this.independentChildrenCount = 0;\n  }\n}\n\n/**\n * Tarjan's algorithm for finding articulation points in graph.\n *\n * @param {Graph} graph\n * @return {Object}\n */\nexport default function articulationPoints(graph) {\n  // Set of vertices we've already visited during DFS.\n  const visitedSet = {};\n\n  // Set of articulation points.\n  const articulationPointsSet = {};\n\n  // Time needed to discover to the current vertex.\n  let discoveryTime = 0;\n\n  // Peek the start vertex for DFS traversal.\n  const startVertex = graph.getAllVertices()[0];\n\n  const dfsCallbacks = {\n    /**\n     * @param {GraphVertex} currentVertex\n     * @param {GraphVertex} previousVertex\n     */\n    enterVertex: ({ currentVertex, previousVertex }) => {\n      // Tick discovery time.\n      discoveryTime += 1;\n\n      // Put current vertex to visited set.\n      visitedSet[currentVertex.getKey()] = new VisitMetadata({\n        discoveryTime,\n        lowDiscoveryTime: discoveryTime,\n      });\n\n      if (previousVertex) {\n        // Update children counter for previous vertex.\n        visitedSet[previousVertex.getKey()].independentChildrenCount += 1;\n      }\n    },\n    /**\n     * @param {GraphVertex} currentVertex\n     * @param {GraphVertex} previousVertex\n     */\n    leaveVertex: ({ currentVertex, previousVertex }) => {\n      if (previousVertex === null) {\n        // Don't do anything for the root vertex if it is already current (not previous one)\n        return;\n      }\n\n      // Update the low time with the smallest time of adjacent vertices.\n      // Get minimum low discovery time from all neighbors.\n      /** @param {GraphVertex} neighbor */\n      visitedSet[currentVertex.getKey()].lowDiscoveryTime = currentVertex.getNeighbors()\n        .filter((earlyNeighbor) => earlyNeighbor.getKey() !== previousVertex.getKey())\n        /**\n         * @param {number} lowestDiscoveryTime\n         * @param {GraphVertex} neighbor\n         */\n        .reduce(\n          (lowestDiscoveryTime, neighbor) => {\n            const neighborLowTime = visitedSet[neighbor.getKey()].lowDiscoveryTime;\n            return neighborLowTime < lowestDiscoveryTime ? neighborLowTime : lowestDiscoveryTime;\n          },\n          visitedSet[currentVertex.getKey()].lowDiscoveryTime,\n        );\n\n      // Detect whether previous vertex is articulation point or not.\n      // To do so we need to check two [OR] conditions:\n      // 1. Is it a root vertex with at least two independent children.\n      // 2. If its visited time is <= low time of adjacent vertex.\n      if (previousVertex === startVertex) {\n        // Check that root vertex has at least two independent children.\n        if (visitedSet[previousVertex.getKey()].independentChildrenCount >= 2) {\n          articulationPointsSet[previousVertex.getKey()] = previousVertex;\n        }\n      } else {\n        // Get current vertex low discovery time.\n        const currentLowDiscoveryTime = visitedSet[currentVertex.getKey()].lowDiscoveryTime;\n\n        // Compare current vertex low discovery time with parent discovery time. Check if there\n        // are any short path (back edge) exists. If we can't get to current vertex other then\n        // via parent then the parent vertex is articulation point for current one.\n        const parentDiscoveryTime = visitedSet[previousVertex.getKey()].discoveryTime;\n        if (parentDiscoveryTime <= currentLowDiscoveryTime) {\n          articulationPointsSet[previousVertex.getKey()] = previousVertex;\n        }\n      }\n    },\n    allowTraversal: ({ nextVertex }) => {\n      return !visitedSet[nextVertex.getKey()];\n    },\n  };\n\n  // Do Depth First Search traversal over submitted graph.\n  depthFirstSearch(graph, startVertex, dfsCallbacks);\n\n  return articulationPointsSet;\n}\n"
  },
  {
    "path": "src/algorithms/graph/bellman-ford/README.md",
    "content": "# Bellman–Ford Algorithm\n\nThe Bellman–Ford algorithm is an algorithm that computes shortest \npaths from a single source vertex to all of the other vertices \nin a weighted digraph. It is slower than Dijkstra's algorithm \nfor the same problem, but more versatile, as it is capable of \nhandling graphs in which some of the edge weights are negative \nnumbers.\n\n![Bellman-Ford](https://upload.wikimedia.org/wikipedia/commons/2/2e/Shortest_path_Dijkstra_vs_BellmanFord.gif)\n\n## Complexity\n\nWorst-case performance `O(|V||E|)`\nBest-case performance\t`O(|E|)`\nWorst-case space complexity `O(|V|)`\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)\n- [On YouTube by Michael Sambol](https://www.youtube.com/watch?v=obWXjtg0L64&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/bellman-ford/__test__/bellmanFord.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport bellmanFord from '../bellmanFord';\n\ndescribe('bellmanFord', () => {\n  it('should find minimum paths to all vertices for undirected graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 4);\n    const edgeAE = new GraphEdge(vertexA, vertexE, 7);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 6);\n    const edgeBD = new GraphEdge(vertexB, vertexD, 5);\n    const edgeEC = new GraphEdge(vertexE, vertexC, 8);\n    const edgeED = new GraphEdge(vertexE, vertexD, 2);\n    const edgeDC = new GraphEdge(vertexD, vertexC, 11);\n    const edgeDG = new GraphEdge(vertexD, vertexG, 10);\n    const edgeDF = new GraphEdge(vertexD, vertexF, 2);\n    const edgeFG = new GraphEdge(vertexF, vertexG, 3);\n    const edgeEG = new GraphEdge(vertexE, vertexG, 5);\n\n    const graph = new Graph();\n    graph\n      .addVertex(vertexH)\n      .addEdge(edgeAB)\n      .addEdge(edgeAE)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeEC)\n      .addEdge(edgeED)\n      .addEdge(edgeDC)\n      .addEdge(edgeDG)\n      .addEdge(edgeDF)\n      .addEdge(edgeFG)\n      .addEdge(edgeEG);\n\n    const { distances, previousVertices } = bellmanFord(graph, vertexA);\n\n    expect(distances).toEqual({\n      H: Infinity,\n      A: 0,\n      B: 4,\n      E: 7,\n      C: 3,\n      D: 9,\n      G: 12,\n      F: 11,\n    });\n\n    expect(previousVertices.F.getKey()).toBe('D');\n    expect(previousVertices.D.getKey()).toBe('B');\n    expect(previousVertices.B.getKey()).toBe('A');\n    expect(previousVertices.G.getKey()).toBe('E');\n    expect(previousVertices.C.getKey()).toBe('A');\n    expect(previousVertices.A).toBeNull();\n    expect(previousVertices.H).toBeNull();\n  });\n\n  it('should find minimum paths to all vertices for directed graph with negative edge weights', () => {\n    const vertexS = new GraphVertex('S');\n    const vertexE = new GraphVertex('E');\n    const vertexA = new GraphVertex('A');\n    const vertexD = new GraphVertex('D');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexH = new GraphVertex('H');\n\n    const edgeSE = new GraphEdge(vertexS, vertexE, 8);\n    const edgeSA = new GraphEdge(vertexS, vertexA, 10);\n    const edgeED = new GraphEdge(vertexE, vertexD, 1);\n    const edgeDA = new GraphEdge(vertexD, vertexA, -4);\n    const edgeDC = new GraphEdge(vertexD, vertexC, -1);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 2);\n    const edgeCB = new GraphEdge(vertexC, vertexB, -2);\n    const edgeBA = new GraphEdge(vertexB, vertexA, 1);\n\n    const graph = new Graph(true);\n    graph\n      .addVertex(vertexH)\n      .addEdge(edgeSE)\n      .addEdge(edgeSA)\n      .addEdge(edgeED)\n      .addEdge(edgeDA)\n      .addEdge(edgeDC)\n      .addEdge(edgeAC)\n      .addEdge(edgeCB)\n      .addEdge(edgeBA);\n\n    const { distances, previousVertices } = bellmanFord(graph, vertexS);\n\n    expect(distances).toEqual({\n      H: Infinity,\n      S: 0,\n      A: 5,\n      B: 5,\n      C: 7,\n      D: 9,\n      E: 8,\n    });\n\n    expect(previousVertices.H).toBeNull();\n    expect(previousVertices.S).toBeNull();\n    expect(previousVertices.B.getKey()).toBe('C');\n    expect(previousVertices.C.getKey()).toBe('A');\n    expect(previousVertices.A.getKey()).toBe('D');\n    expect(previousVertices.D.getKey()).toBe('E');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/bellman-ford/bellmanFord.js",
    "content": "/**\n * @param {Graph} graph\n * @param {GraphVertex} startVertex\n * @return {{distances, previousVertices}}\n */\nexport default function bellmanFord(graph, startVertex) {\n  const distances = {};\n  const previousVertices = {};\n\n  // Init all distances with infinity assuming that currently we can't reach\n  // any of the vertices except start one.\n  distances[startVertex.getKey()] = 0;\n  graph.getAllVertices().forEach((vertex) => {\n    previousVertices[vertex.getKey()] = null;\n    if (vertex.getKey() !== startVertex.getKey()) {\n      distances[vertex.getKey()] = Infinity;\n    }\n  });\n\n  // We need (|V| - 1) iterations.\n  for (let iteration = 0; iteration < (graph.getAllVertices().length - 1); iteration += 1) {\n    // During each iteration go through all vertices.\n    Object.keys(distances).forEach((vertexKey) => {\n      const vertex = graph.getVertexByKey(vertexKey);\n\n      // Go through all vertex edges.\n      graph.getNeighbors(vertex).forEach((neighbor) => {\n        const edge = graph.findEdge(vertex, neighbor);\n        // Find out if the distance to the neighbor is shorter in this iteration\n        // then in previous one.\n        const distanceToVertex = distances[vertex.getKey()];\n        const distanceToNeighbor = distanceToVertex + edge.weight;\n        if (distanceToNeighbor < distances[neighbor.getKey()]) {\n          distances[neighbor.getKey()] = distanceToNeighbor;\n          previousVertices[neighbor.getKey()] = vertex;\n        }\n      });\n    });\n  }\n\n  return {\n    distances,\n    previousVertices,\n  };\n}\n"
  },
  {
    "path": "src/algorithms/graph/breadth-first-search/README.md",
    "content": "# Breadth-First Search (BFS)\n\nBreadth-first search (BFS) is an algorithm for traversing, \nsearching tree, or graph data structures. It starts at\nthe tree root (or some arbitrary node of a graph, sometimes \nreferred to as a 'search key') and explores the neighbor\nnodes first, before moving to the next level neighbors.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search)\n- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)\n- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)\n- [BFS Visualization](https://www.cs.usfca.edu/~galles/visualization/BFS.html)\n"
  },
  {
    "path": "src/algorithms/graph/breadth-first-search/__test__/breadthFirstSearch.test.js",
    "content": "import Graph from '../../../../data-structures/graph/Graph';\nimport GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport breadthFirstSearch from '../breadthFirstSearch';\n\ndescribe('breadthFirstSearch', () => {\n  it('should perform BFS operation on graph', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCG = new GraphEdge(vertexC, vertexG);\n    const edgeAD = new GraphEdge(vertexA, vertexD);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeFD = new GraphEdge(vertexF, vertexD);\n    const edgeDH = new GraphEdge(vertexD, vertexH);\n    const edgeGH = new GraphEdge(vertexG, vertexH);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCG)\n      .addEdge(edgeAD)\n      .addEdge(edgeAE)\n      .addEdge(edgeEF)\n      .addEdge(edgeFD)\n      .addEdge(edgeDH)\n      .addEdge(edgeGH);\n\n    expect(graph.toString()).toBe('A,B,C,G,D,E,F,H');\n\n    const enterVertexCallback = jest.fn();\n    const leaveVertexCallback = jest.fn();\n\n    // Traverse graphs without callbacks first.\n    breadthFirstSearch(graph, vertexA);\n\n    // Traverse graph with enterVertex and leaveVertex callbacks.\n    breadthFirstSearch(graph, vertexA, {\n      enterVertex: enterVertexCallback,\n      leaveVertex: leaveVertexCallback,\n    });\n\n    expect(enterVertexCallback).toHaveBeenCalledTimes(8);\n    expect(leaveVertexCallback).toHaveBeenCalledTimes(8);\n\n    const enterVertexParamsMap = [\n      { currentVertex: vertexA, previousVertex: null },\n      { currentVertex: vertexB, previousVertex: vertexA },\n      { currentVertex: vertexD, previousVertex: vertexB },\n      { currentVertex: vertexE, previousVertex: vertexD },\n      { currentVertex: vertexC, previousVertex: vertexE },\n      { currentVertex: vertexH, previousVertex: vertexC },\n      { currentVertex: vertexF, previousVertex: vertexH },\n      { currentVertex: vertexG, previousVertex: vertexF },\n    ];\n\n    for (let callIndex = 0; callIndex < graph.getAllVertices().length; callIndex += 1) {\n      const params = enterVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(enterVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(enterVertexParamsMap[callIndex].previousVertex);\n    }\n\n    const leaveVertexParamsMap = [\n      { currentVertex: vertexA, previousVertex: null },\n      { currentVertex: vertexB, previousVertex: vertexA },\n      { currentVertex: vertexD, previousVertex: vertexB },\n      { currentVertex: vertexE, previousVertex: vertexD },\n      { currentVertex: vertexC, previousVertex: vertexE },\n      { currentVertex: vertexH, previousVertex: vertexC },\n      { currentVertex: vertexF, previousVertex: vertexH },\n      { currentVertex: vertexG, previousVertex: vertexF },\n    ];\n\n    for (let callIndex = 0; callIndex < graph.getAllVertices().length; callIndex += 1) {\n      const params = leaveVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(leaveVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(leaveVertexParamsMap[callIndex].previousVertex);\n    }\n  });\n\n  it('should allow to create custom vertex visiting logic', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCG = new GraphEdge(vertexC, vertexG);\n    const edgeAD = new GraphEdge(vertexA, vertexD);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeFD = new GraphEdge(vertexF, vertexD);\n    const edgeDH = new GraphEdge(vertexD, vertexH);\n    const edgeGH = new GraphEdge(vertexG, vertexH);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCG)\n      .addEdge(edgeAD)\n      .addEdge(edgeAE)\n      .addEdge(edgeEF)\n      .addEdge(edgeFD)\n      .addEdge(edgeDH)\n      .addEdge(edgeGH);\n\n    expect(graph.toString()).toBe('A,B,C,G,D,E,F,H');\n\n    const enterVertexCallback = jest.fn();\n    const leaveVertexCallback = jest.fn();\n\n    // Traverse graph with enterVertex and leaveVertex callbacks.\n    breadthFirstSearch(graph, vertexA, {\n      enterVertex: enterVertexCallback,\n      leaveVertex: leaveVertexCallback,\n      allowTraversal: ({ currentVertex, nextVertex }) => {\n        return !(currentVertex === vertexA && nextVertex === vertexB);\n      },\n    });\n\n    expect(enterVertexCallback).toHaveBeenCalledTimes(7);\n    expect(leaveVertexCallback).toHaveBeenCalledTimes(7);\n\n    const enterVertexParamsMap = [\n      { currentVertex: vertexA, previousVertex: null },\n      { currentVertex: vertexD, previousVertex: vertexA },\n      { currentVertex: vertexE, previousVertex: vertexD },\n      { currentVertex: vertexH, previousVertex: vertexE },\n      { currentVertex: vertexF, previousVertex: vertexH },\n      { currentVertex: vertexD, previousVertex: vertexF },\n      { currentVertex: vertexH, previousVertex: vertexD },\n    ];\n\n    for (let callIndex = 0; callIndex < 7; callIndex += 1) {\n      const params = enterVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(enterVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(enterVertexParamsMap[callIndex].previousVertex);\n    }\n\n    const leaveVertexParamsMap = [\n      { currentVertex: vertexA, previousVertex: null },\n      { currentVertex: vertexD, previousVertex: vertexA },\n      { currentVertex: vertexE, previousVertex: vertexD },\n      { currentVertex: vertexH, previousVertex: vertexE },\n      { currentVertex: vertexF, previousVertex: vertexH },\n      { currentVertex: vertexD, previousVertex: vertexF },\n      { currentVertex: vertexH, previousVertex: vertexD },\n    ];\n\n    for (let callIndex = 0; callIndex < 7; callIndex += 1) {\n      const params = leaveVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(leaveVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(leaveVertexParamsMap[callIndex].previousVertex);\n    }\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/breadth-first-search/breadthFirstSearch.js",
    "content": "import Queue from '../../../data-structures/queue/Queue';\n\n/**\n * @typedef {Object} Callbacks\n *\n * @property {function(vertices: Object): boolean} [allowTraversal] -\n *   Determines whether DFS should traverse from the vertex to its neighbor\n *   (along the edge). By default prohibits visiting the same vertex again.\n *\n * @property {function(vertices: Object)} [enterVertex] - Called when BFS enters the vertex.\n *\n * @property {function(vertices: Object)} [leaveVertex] - Called when BFS leaves the vertex.\n */\n\n/**\n * @param {Callbacks} [callbacks]\n * @returns {Callbacks}\n */\nfunction initCallbacks(callbacks = {}) {\n  const initiatedCallback = callbacks;\n\n  const stubCallback = () => {};\n\n  const allowTraversalCallback = (\n    () => {\n      const seen = {};\n      return ({ nextVertex }) => {\n        if (!seen[nextVertex.getKey()]) {\n          seen[nextVertex.getKey()] = true;\n          return true;\n        }\n        return false;\n      };\n    }\n  )();\n\n  initiatedCallback.allowTraversal = callbacks.allowTraversal || allowTraversalCallback;\n  initiatedCallback.enterVertex = callbacks.enterVertex || stubCallback;\n  initiatedCallback.leaveVertex = callbacks.leaveVertex || stubCallback;\n\n  return initiatedCallback;\n}\n\n/**\n * @param {Graph} graph\n * @param {GraphVertex} startVertex\n * @param {Callbacks} [originalCallbacks]\n */\nexport default function breadthFirstSearch(graph, startVertex, originalCallbacks) {\n  const callbacks = initCallbacks(originalCallbacks);\n  const vertexQueue = new Queue();\n\n  // Do initial queue setup.\n  vertexQueue.enqueue(startVertex);\n\n  let previousVertex = null;\n\n  // Traverse all vertices from the queue.\n  while (!vertexQueue.isEmpty()) {\n    const currentVertex = vertexQueue.dequeue();\n    callbacks.enterVertex({ currentVertex, previousVertex });\n\n    // Add all neighbors to the queue for future traversals.\n    graph.getNeighbors(currentVertex).forEach((nextVertex) => {\n      if (callbacks.allowTraversal({ previousVertex, currentVertex, nextVertex })) {\n        vertexQueue.enqueue(nextVertex);\n      }\n    });\n\n    callbacks.leaveVertex({ currentVertex, previousVertex });\n\n    // Memorize current vertex before next loop.\n    previousVertex = currentVertex;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/graph/bridges/README.md",
    "content": "# Bridges in Graph\n\nIn graph theory, a **bridge**, **isthmus**, **cut-edge**, or **cut arc** is an edge \nof a graph whose deletion increases its number of connected components. Equivalently, \nan edge is a bridge if and only if it is not contained in any cycle. A graph is said \nto be bridgeless or isthmus-free if it contains no bridges.\n\n![Bridges in graph](https://upload.wikimedia.org/wikipedia/commons/d/df/Graph_cut_edges.svg)\n\nA graph with 16 vertices and 6 bridges (highlighted in red)\n\n![Bridgeless](https://upload.wikimedia.org/wikipedia/commons/b/bf/Undirected.svg)\n\nAn undirected connected graph with no cut edges\n\n![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge1.png)\n\n![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge2.png)\n\n![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge3.png)\n\n## References\n\n- [GeeksForGeeks on YouTube](https://www.youtube.com/watch?v=thLQYBlz2DM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Wikipedia](https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29#Tarjan.27s_Bridge-finding_algorithm)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/bridge-in-a-graph/)\n"
  },
  {
    "path": "src/algorithms/graph/bridges/__test__/graphBridges.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport graphBridges from '../graphBridges';\n\ndescribe('graphBridges', () => {\n  it('should find bridges in simple graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD);\n\n    const bridges = Object.values(graphBridges(graph));\n\n    expect(bridges.length).toBe(3);\n    expect(bridges[0].getKey()).toBe(edgeCD.getKey());\n    expect(bridges[1].getKey()).toBe(edgeBC.getKey());\n    expect(bridges[2].getKey()).toBe(edgeAB.getKey());\n  });\n\n  it('should find bridges in simple graph with back edge', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD);\n\n    const bridges = Object.values(graphBridges(graph));\n\n    expect(bridges.length).toBe(1);\n    expect(bridges[0].getKey()).toBe(edgeCD.getKey());\n  });\n\n  it('should find bridges in graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n    const edgeEG = new GraphEdge(vertexE, vertexG);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeGF = new GraphEdge(vertexG, vertexF);\n    const edgeFH = new GraphEdge(vertexF, vertexH);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeAC)\n      .addEdge(edgeCD)\n      .addEdge(edgeDE)\n      .addEdge(edgeEG)\n      .addEdge(edgeEF)\n      .addEdge(edgeGF)\n      .addEdge(edgeFH);\n\n    const bridges = Object.values(graphBridges(graph));\n\n    expect(bridges.length).toBe(3);\n    expect(bridges[0].getKey()).toBe(edgeFH.getKey());\n    expect(bridges[1].getKey()).toBe(edgeDE.getKey());\n    expect(bridges[2].getKey()).toBe(edgeCD.getKey());\n  });\n\n  it('should find bridges in graph starting with different root vertex', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n    const edgeEG = new GraphEdge(vertexE, vertexG);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeGF = new GraphEdge(vertexG, vertexF);\n    const edgeFH = new GraphEdge(vertexF, vertexH);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeDE)\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeAC)\n      .addEdge(edgeCD)\n      .addEdge(edgeEG)\n      .addEdge(edgeEF)\n      .addEdge(edgeGF)\n      .addEdge(edgeFH);\n\n    const bridges = Object.values(graphBridges(graph));\n\n    expect(bridges.length).toBe(3);\n    expect(bridges[0].getKey()).toBe(edgeFH.getKey());\n    expect(bridges[1].getKey()).toBe(edgeDE.getKey());\n    expect(bridges[2].getKey()).toBe(edgeCD.getKey());\n  });\n\n  it('should find bridges in yet another graph #1', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeDE);\n\n    const bridges = Object.values(graphBridges(graph));\n\n    expect(bridges.length).toBe(2);\n    expect(bridges[0].getKey()).toBe(edgeDE.getKey());\n    expect(bridges[1].getKey()).toBe(edgeCD.getKey());\n  });\n\n  it('should find bridges in yet another graph #2', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeCE = new GraphEdge(vertexC, vertexE);\n    const edgeCF = new GraphEdge(vertexC, vertexF);\n    const edgeEG = new GraphEdge(vertexE, vertexG);\n    const edgeFG = new GraphEdge(vertexF, vertexG);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeCE)\n      .addEdge(edgeCF)\n      .addEdge(edgeEG)\n      .addEdge(edgeFG);\n\n    const bridges = Object.values(graphBridges(graph));\n\n    expect(bridges.length).toBe(1);\n    expect(bridges[0].getKey()).toBe(edgeCD.getKey());\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/bridges/graphBridges.js",
    "content": "import depthFirstSearch from '../depth-first-search/depthFirstSearch';\n\n/**\n * Helper class for visited vertex metadata.\n */\nclass VisitMetadata {\n  constructor({ discoveryTime, lowDiscoveryTime }) {\n    this.discoveryTime = discoveryTime;\n    this.lowDiscoveryTime = lowDiscoveryTime;\n  }\n}\n\n/**\n * @param {Graph} graph\n * @return {Object}\n */\nexport default function graphBridges(graph) {\n  // Set of vertices we've already visited during DFS.\n  const visitedSet = {};\n\n  // Set of bridges.\n  const bridges = {};\n\n  // Time needed to discover to the current vertex.\n  let discoveryTime = 0;\n\n  // Peek the start vertex for DFS traversal.\n  const startVertex = graph.getAllVertices()[0];\n\n  const dfsCallbacks = {\n    /**\n     * @param {GraphVertex} currentVertex\n     */\n    enterVertex: ({ currentVertex }) => {\n      // Tick discovery time.\n      discoveryTime += 1;\n\n      // Put current vertex to visited set.\n      visitedSet[currentVertex.getKey()] = new VisitMetadata({\n        discoveryTime,\n        lowDiscoveryTime: discoveryTime,\n      });\n    },\n    /**\n     * @param {GraphVertex} currentVertex\n     * @param {GraphVertex} previousVertex\n     */\n    leaveVertex: ({ currentVertex, previousVertex }) => {\n      if (previousVertex === null) {\n        // Don't do anything for the root vertex if it is already current (not previous one).\n        return;\n      }\n\n      // Check if current node is connected to any early node other then previous one.\n      visitedSet[currentVertex.getKey()].lowDiscoveryTime = currentVertex.getNeighbors()\n        .filter((earlyNeighbor) => earlyNeighbor.getKey() !== previousVertex.getKey())\n        .reduce(\n          /**\n           * @param {number} lowestDiscoveryTime\n           * @param {GraphVertex} neighbor\n           */\n          (lowestDiscoveryTime, neighbor) => {\n            const neighborLowTime = visitedSet[neighbor.getKey()].lowDiscoveryTime;\n            return neighborLowTime < lowestDiscoveryTime ? neighborLowTime : lowestDiscoveryTime;\n          },\n          visitedSet[currentVertex.getKey()].lowDiscoveryTime,\n        );\n\n      // Compare low discovery times. In case if current low discovery time is less than the one\n      // in previous vertex then update previous vertex low time.\n      const currentLowDiscoveryTime = visitedSet[currentVertex.getKey()].lowDiscoveryTime;\n      const previousLowDiscoveryTime = visitedSet[previousVertex.getKey()].lowDiscoveryTime;\n      if (currentLowDiscoveryTime < previousLowDiscoveryTime) {\n        visitedSet[previousVertex.getKey()].lowDiscoveryTime = currentLowDiscoveryTime;\n      }\n\n      // Compare current vertex low discovery time with parent discovery time. Check if there\n      // are any short path (back edge) exists. If we can't get to current vertex other then\n      // via parent then the parent vertex is articulation point for current one.\n      const parentDiscoveryTime = visitedSet[previousVertex.getKey()].discoveryTime;\n      if (parentDiscoveryTime < currentLowDiscoveryTime) {\n        const bridge = graph.findEdge(previousVertex, currentVertex);\n        bridges[bridge.getKey()] = bridge;\n      }\n    },\n    allowTraversal: ({ nextVertex }) => {\n      return !visitedSet[nextVertex.getKey()];\n    },\n  };\n\n  // Do Depth First Search traversal over submitted graph.\n  depthFirstSearch(graph, startVertex, dfsCallbacks);\n\n  return bridges;\n}\n"
  },
  {
    "path": "src/algorithms/graph/depth-first-search/README.md",
    "content": "# Depth-First Search (DFS)\n\nDepth-first search (DFS) is an algorithm for traversing or \nsearching tree or graph data structures. One starts at \nthe root (selecting some arbitrary node as the root in \nthe case of a graph) and explores as far as possible \nalong each branch before backtracking.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search)\n- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)\n- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)\n- [DFS Visualization](https://www.cs.usfca.edu/~galles/visualization/DFS.html)\n"
  },
  {
    "path": "src/algorithms/graph/depth-first-search/__test__/depthFirstSearch.test.js",
    "content": "import Graph from '../../../../data-structures/graph/Graph';\nimport GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport depthFirstSearch from '../depthFirstSearch';\n\ndescribe('depthFirstSearch', () => {\n  it('should perform DFS operation on graph', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCG = new GraphEdge(vertexC, vertexG);\n    const edgeAD = new GraphEdge(vertexA, vertexD);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeFD = new GraphEdge(vertexF, vertexD);\n    const edgeDG = new GraphEdge(vertexD, vertexG);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCG)\n      .addEdge(edgeAD)\n      .addEdge(edgeAE)\n      .addEdge(edgeEF)\n      .addEdge(edgeFD)\n      .addEdge(edgeDG);\n\n    expect(graph.toString()).toBe('A,B,C,G,D,E,F');\n\n    const enterVertexCallback = jest.fn();\n    const leaveVertexCallback = jest.fn();\n\n    // Traverse graphs without callbacks first to check default ones.\n    depthFirstSearch(graph, vertexA);\n\n    // Traverse graph with enterVertex and leaveVertex callbacks.\n    depthFirstSearch(graph, vertexA, {\n      enterVertex: enterVertexCallback,\n      leaveVertex: leaveVertexCallback,\n    });\n\n    expect(enterVertexCallback).toHaveBeenCalledTimes(graph.getAllVertices().length);\n    expect(leaveVertexCallback).toHaveBeenCalledTimes(graph.getAllVertices().length);\n\n    const enterVertexParamsMap = [\n      { currentVertex: vertexA, previousVertex: null },\n      { currentVertex: vertexB, previousVertex: vertexA },\n      { currentVertex: vertexC, previousVertex: vertexB },\n      { currentVertex: vertexG, previousVertex: vertexC },\n      { currentVertex: vertexD, previousVertex: vertexA },\n      { currentVertex: vertexE, previousVertex: vertexA },\n      { currentVertex: vertexF, previousVertex: vertexE },\n    ];\n\n    for (let callIndex = 0; callIndex < graph.getAllVertices().length; callIndex += 1) {\n      const params = enterVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(enterVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(enterVertexParamsMap[callIndex].previousVertex);\n    }\n\n    const leaveVertexParamsMap = [\n      { currentVertex: vertexG, previousVertex: vertexC },\n      { currentVertex: vertexC, previousVertex: vertexB },\n      { currentVertex: vertexB, previousVertex: vertexA },\n      { currentVertex: vertexD, previousVertex: vertexA },\n      { currentVertex: vertexF, previousVertex: vertexE },\n      { currentVertex: vertexE, previousVertex: vertexA },\n      { currentVertex: vertexA, previousVertex: null },\n    ];\n\n    for (let callIndex = 0; callIndex < graph.getAllVertices().length; callIndex += 1) {\n      const params = leaveVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(leaveVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(leaveVertexParamsMap[callIndex].previousVertex);\n    }\n  });\n\n  it('allow users to redefine vertex visiting logic', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCG = new GraphEdge(vertexC, vertexG);\n    const edgeAD = new GraphEdge(vertexA, vertexD);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeFD = new GraphEdge(vertexF, vertexD);\n    const edgeDG = new GraphEdge(vertexD, vertexG);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCG)\n      .addEdge(edgeAD)\n      .addEdge(edgeAE)\n      .addEdge(edgeEF)\n      .addEdge(edgeFD)\n      .addEdge(edgeDG);\n\n    expect(graph.toString()).toBe('A,B,C,G,D,E,F');\n\n    const enterVertexCallback = jest.fn();\n    const leaveVertexCallback = jest.fn();\n\n    depthFirstSearch(graph, vertexA, {\n      enterVertex: enterVertexCallback,\n      leaveVertex: leaveVertexCallback,\n      allowTraversal: ({ currentVertex, nextVertex }) => {\n        return !(currentVertex === vertexA && nextVertex === vertexB);\n      },\n    });\n\n    expect(enterVertexCallback).toHaveBeenCalledTimes(7);\n    expect(leaveVertexCallback).toHaveBeenCalledTimes(7);\n\n    const enterVertexParamsMap = [\n      { currentVertex: vertexA, previousVertex: null },\n      { currentVertex: vertexD, previousVertex: vertexA },\n      { currentVertex: vertexG, previousVertex: vertexD },\n      { currentVertex: vertexE, previousVertex: vertexA },\n      { currentVertex: vertexF, previousVertex: vertexE },\n      { currentVertex: vertexD, previousVertex: vertexF },\n      { currentVertex: vertexG, previousVertex: vertexD },\n    ];\n\n    for (let callIndex = 0; callIndex < graph.getAllVertices().length; callIndex += 1) {\n      const params = enterVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(enterVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(enterVertexParamsMap[callIndex].previousVertex);\n    }\n\n    const leaveVertexParamsMap = [\n      { currentVertex: vertexG, previousVertex: vertexD },\n      { currentVertex: vertexD, previousVertex: vertexA },\n      { currentVertex: vertexG, previousVertex: vertexD },\n      { currentVertex: vertexD, previousVertex: vertexF },\n      { currentVertex: vertexF, previousVertex: vertexE },\n      { currentVertex: vertexE, previousVertex: vertexA },\n      { currentVertex: vertexA, previousVertex: null },\n    ];\n\n    for (let callIndex = 0; callIndex < graph.getAllVertices().length; callIndex += 1) {\n      const params = leaveVertexCallback.mock.calls[callIndex][0];\n      expect(params.currentVertex).toEqual(leaveVertexParamsMap[callIndex].currentVertex);\n      expect(params.previousVertex).toEqual(leaveVertexParamsMap[callIndex].previousVertex);\n    }\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/depth-first-search/depthFirstSearch.js",
    "content": "/**\n * @typedef {Object} Callbacks\n *\n * @property {function(vertices: Object): boolean} [allowTraversal] -\n *  Determines whether DFS should traverse from the vertex to its neighbor\n *  (along the edge). By default prohibits visiting the same vertex again.\n *\n * @property {function(vertices: Object)} [enterVertex] - Called when DFS enters the vertex.\n *\n * @property {function(vertices: Object)} [leaveVertex] - Called when DFS leaves the vertex.\n */\n\n/**\n * @param {Callbacks} [callbacks]\n * @returns {Callbacks}\n */\nfunction initCallbacks(callbacks = {}) {\n  const initiatedCallback = callbacks;\n\n  const stubCallback = () => {};\n\n  const allowTraversalCallback = (\n    () => {\n      const seen = {};\n      return ({ nextVertex }) => {\n        if (!seen[nextVertex.getKey()]) {\n          seen[nextVertex.getKey()] = true;\n          return true;\n        }\n        return false;\n      };\n    }\n  )();\n\n  initiatedCallback.allowTraversal = callbacks.allowTraversal || allowTraversalCallback;\n  initiatedCallback.enterVertex = callbacks.enterVertex || stubCallback;\n  initiatedCallback.leaveVertex = callbacks.leaveVertex || stubCallback;\n\n  return initiatedCallback;\n}\n\n/**\n * @param {Graph} graph\n * @param {GraphVertex} currentVertex\n * @param {GraphVertex} previousVertex\n * @param {Callbacks} callbacks\n */\nfunction depthFirstSearchRecursive(graph, currentVertex, previousVertex, callbacks) {\n  callbacks.enterVertex({ currentVertex, previousVertex });\n\n  graph.getNeighbors(currentVertex).forEach((nextVertex) => {\n    if (callbacks.allowTraversal({ previousVertex, currentVertex, nextVertex })) {\n      depthFirstSearchRecursive(graph, nextVertex, currentVertex, callbacks);\n    }\n  });\n\n  callbacks.leaveVertex({ currentVertex, previousVertex });\n}\n\n/**\n * @param {Graph} graph\n * @param {GraphVertex} startVertex\n * @param {Callbacks} [callbacks]\n */\nexport default function depthFirstSearch(graph, startVertex, callbacks) {\n  const previousVertex = null;\n  depthFirstSearchRecursive(graph, startVertex, previousVertex, initCallbacks(callbacks));\n}\n"
  },
  {
    "path": "src/algorithms/graph/detect-cycle/README.md",
    "content": "# Detect Cycle in Graphs\n\nIn graph theory, a **cycle** is a path of edges and vertices \nwherein a vertex is reachable from itself. There are several \ndifferent types of cycles, principally a **closed walk** and \na **simple cycle**.\n\n## Definitions\n\nA **closed walk** consists of a sequence of vertices starting \nand ending at the same vertex, with each two consecutive vertices\nin the sequence adjacent to each other in the graph. In a directed graph,\neach edge must be traversed by the walk consistently with its direction: \nthe edge must be oriented from the earlier of two consecutive vertices \nto the later of the two vertices in the sequence. \nThe choice of starting vertex is not important: traversing the same cyclic \nsequence of edges from different starting vertices produces the same closed walk.\n\nA **simple cycle may** be defined either as a closed walk with no repetitions of \nvertices and edges allowed, other than the repetition of the starting and ending \nvertex, or as the set of edges in such a walk. The two definitions are equivalent \nin directed graphs, where simple cycles are also called directed cycles: the cyclic \nsequence of vertices and edges in a walk is completely determined by the set of \nedges that it uses. In undirected graphs the set of edges of a cycle can be \ntraversed by a walk in either of two directions, giving two possible directed cycles \nfor every undirected cycle. A circuit can be a closed walk allowing repetitions of \nvertices but not edges; however, it can also be a simple cycle, so explicit \ndefinition is recommended when it is used.\n\n## Example\n\n![Cycles](https://upload.wikimedia.org/wikipedia/commons/e/e7/Graph_cycle.gif)\n\nA graph with edges colored to illustrate **path** `H-A-B` (green), closed path or \n**walk with a repeated vertex** `B-D-E-F-D-C-B` (blue) and a **cycle with no repeated edge** or \nvertex `H-D-G-H` (red)\n\n### Cycle in undirected graph\n\n![Undirected Cycle](https://www.geeksforgeeks.org/wp-content/uploads/cycleGraph.png)\n\n### Cycle in directed graph\n\n![Directed Cycle](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/cycle.png)\n\n## References\n\nGeneral information:\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Cycle_(graph_theory))\n\nCycles in undirected graphs:\n\n- [Detect Cycle in Undirected Graph on GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-undirected-graph/)\n- [Detect Cycle in Undirected Graph Algorithm on YouTube](https://www.youtube.com/watch?v=n_t0a_8H8VY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\nCycles in directed graphs:\n\n- [Detect Cycle in Directed Graph on GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-in-a-graph/)\n- [Detect Cycle in Directed Graph Algorithm on YouTube](https://www.youtube.com/watch?v=rKQaZuoUR4M&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/detect-cycle/__test__/detectDirectedCycle.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport detectDirectedCycle from '../detectDirectedCycle';\n\ndescribe('detectDirectedCycle', () => {\n  it('should detect directed cycle', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeDA = new GraphEdge(vertexD, vertexA);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeFD = new GraphEdge(vertexF, vertexD);\n\n    const graph = new Graph(true);\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeAC)\n      .addEdge(edgeDA)\n      .addEdge(edgeDE)\n      .addEdge(edgeEF);\n\n    expect(detectDirectedCycle(graph)).toBeNull();\n\n    graph.addEdge(edgeFD);\n\n    expect(detectDirectedCycle(graph)).toEqual({\n      D: vertexF,\n      F: vertexE,\n      E: vertexD,\n    });\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/detect-cycle/__test__/detectUndirectedCycle.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport detectUndirectedCycle from '../detectUndirectedCycle';\n\ndescribe('detectUndirectedCycle', () => {\n  it('should detect undirected cycle', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n\n    const edgeAF = new GraphEdge(vertexA, vertexF);\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBE = new GraphEdge(vertexB, vertexE);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n\n    const graph = new Graph();\n    graph\n      .addEdge(edgeAF)\n      .addEdge(edgeAB)\n      .addEdge(edgeBE)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD);\n\n    expect(detectUndirectedCycle(graph)).toBeNull();\n\n    graph.addEdge(edgeDE);\n\n    expect(detectUndirectedCycle(graph)).toEqual({\n      B: vertexC,\n      C: vertexD,\n      D: vertexE,\n      E: vertexB,\n    });\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/detect-cycle/__test__/detectUndirectedCycleUsingDisjointSet.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport detectUndirectedCycleUsingDisjointSet from '../detectUndirectedCycleUsingDisjointSet';\n\ndescribe('detectUndirectedCycleUsingDisjointSet', () => {\n  it('should detect undirected cycle', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n\n    const edgeAF = new GraphEdge(vertexA, vertexF);\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBE = new GraphEdge(vertexB, vertexE);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n\n    const graph = new Graph();\n    graph\n      .addEdge(edgeAF)\n      .addEdge(edgeAB)\n      .addEdge(edgeBE)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD);\n\n    expect(detectUndirectedCycleUsingDisjointSet(graph)).toBe(false);\n\n    graph.addEdge(edgeDE);\n\n    expect(detectUndirectedCycleUsingDisjointSet(graph)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/detect-cycle/detectDirectedCycle.js",
    "content": "import depthFirstSearch from '../depth-first-search/depthFirstSearch';\n\n/**\n * Detect cycle in directed graph using Depth First Search.\n *\n * @param {Graph} graph\n */\nexport default function detectDirectedCycle(graph) {\n  let cycle = null;\n\n  // Will store parents (previous vertices) for all visited nodes.\n  // This will be needed in order to specify what path exactly is a cycle.\n  const dfsParentMap = {};\n\n  // White set (UNVISITED) contains all the vertices that haven't been visited at all.\n  const whiteSet = {};\n\n  // Gray set (VISITING) contains all the vertices that are being visited right now\n  // (in current path).\n  const graySet = {};\n\n  // Black set (VISITED) contains all the vertices that has been fully visited.\n  // Meaning that all children of the vertex has been visited.\n  const blackSet = {};\n\n  // If we encounter vertex in gray set it means that we've found a cycle.\n  // Because when vertex in gray set it means that its neighbors or its neighbors\n  // neighbors are still being explored.\n\n  // Init white set and add all vertices to it.\n  /** @param {GraphVertex} vertex */\n  graph.getAllVertices().forEach((vertex) => {\n    whiteSet[vertex.getKey()] = vertex;\n  });\n\n  // Describe BFS callbacks.\n  const callbacks = {\n    enterVertex: ({ currentVertex, previousVertex }) => {\n      if (graySet[currentVertex.getKey()]) {\n        // If current vertex already in grey set it means that cycle is detected.\n        // Let's detect cycle path.\n        cycle = {};\n\n        let currentCycleVertex = currentVertex;\n        let previousCycleVertex = previousVertex;\n\n        while (previousCycleVertex.getKey() !== currentVertex.getKey()) {\n          cycle[currentCycleVertex.getKey()] = previousCycleVertex;\n          currentCycleVertex = previousCycleVertex;\n          previousCycleVertex = dfsParentMap[previousCycleVertex.getKey()];\n        }\n\n        cycle[currentCycleVertex.getKey()] = previousCycleVertex;\n      } else {\n        // Otherwise let's add current vertex to gray set and remove it from white set.\n        graySet[currentVertex.getKey()] = currentVertex;\n        delete whiteSet[currentVertex.getKey()];\n\n        // Update DFS parents list.\n        dfsParentMap[currentVertex.getKey()] = previousVertex;\n      }\n    },\n    leaveVertex: ({ currentVertex }) => {\n      // If all node's children has been visited let's remove it from gray set\n      // and move it to the black set meaning that all its neighbors are visited.\n      blackSet[currentVertex.getKey()] = currentVertex;\n      delete graySet[currentVertex.getKey()];\n    },\n    allowTraversal: ({ nextVertex }) => {\n      // If cycle was detected we must forbid all further traversing since it will\n      // cause infinite traversal loop.\n      if (cycle) {\n        return false;\n      }\n\n      // Allow traversal only for the vertices that are not in black set\n      // since all black set vertices have been already visited.\n      return !blackSet[nextVertex.getKey()];\n    },\n  };\n\n  // Start exploring vertices.\n  while (Object.keys(whiteSet).length) {\n    // Pick fist vertex to start BFS from.\n    const firstWhiteKey = Object.keys(whiteSet)[0];\n    const startVertex = whiteSet[firstWhiteKey];\n\n    // Do Depth First Search.\n    depthFirstSearch(graph, startVertex, callbacks);\n  }\n\n  return cycle;\n}\n"
  },
  {
    "path": "src/algorithms/graph/detect-cycle/detectUndirectedCycle.js",
    "content": "import depthFirstSearch from '../depth-first-search/depthFirstSearch';\n\n/**\n * Detect cycle in undirected graph using Depth First Search.\n *\n * @param {Graph} graph\n */\nexport default function detectUndirectedCycle(graph) {\n  let cycle = null;\n\n  // List of vertices that we have visited.\n  const visitedVertices = {};\n\n  // List of parents vertices for every visited vertex.\n  const parents = {};\n\n  // Callbacks for DFS traversing.\n  const callbacks = {\n    allowTraversal: ({ currentVertex, nextVertex }) => {\n      // Don't allow further traversal in case if cycle has been detected.\n      if (cycle) {\n        return false;\n      }\n\n      // Don't allow traversal from child back to its parent.\n      const currentVertexParent = parents[currentVertex.getKey()];\n      const currentVertexParentKey = currentVertexParent ? currentVertexParent.getKey() : null;\n\n      return currentVertexParentKey !== nextVertex.getKey();\n    },\n    enterVertex: ({ currentVertex, previousVertex }) => {\n      if (visitedVertices[currentVertex.getKey()]) {\n        // Compile cycle path based on parents of previous vertices.\n        cycle = {};\n\n        let currentCycleVertex = currentVertex;\n        let previousCycleVertex = previousVertex;\n\n        while (previousCycleVertex.getKey() !== currentVertex.getKey()) {\n          cycle[currentCycleVertex.getKey()] = previousCycleVertex;\n          currentCycleVertex = previousCycleVertex;\n          previousCycleVertex = parents[previousCycleVertex.getKey()];\n        }\n\n        cycle[currentCycleVertex.getKey()] = previousCycleVertex;\n      } else {\n        // Add next vertex to visited set.\n        visitedVertices[currentVertex.getKey()] = currentVertex;\n        parents[currentVertex.getKey()] = previousVertex;\n      }\n    },\n  };\n\n  // Start DFS traversing.\n  const startVertex = graph.getAllVertices()[0];\n  depthFirstSearch(graph, startVertex, callbacks);\n\n  return cycle;\n}\n"
  },
  {
    "path": "src/algorithms/graph/detect-cycle/detectUndirectedCycleUsingDisjointSet.js",
    "content": "import DisjointSet from '../../../data-structures/disjoint-set/DisjointSet';\n\n/**\n * Detect cycle in undirected graph using disjoint sets.\n *\n * @param {Graph} graph\n */\nexport default function detectUndirectedCycleUsingDisjointSet(graph) {\n  // Create initial singleton disjoint sets for each graph vertex.\n  /** @param {GraphVertex} graphVertex */\n  const keyExtractor = (graphVertex) => graphVertex.getKey();\n  const disjointSet = new DisjointSet(keyExtractor);\n  graph.getAllVertices().forEach((graphVertex) => disjointSet.makeSet(graphVertex));\n\n  // Go trough all graph edges one by one and check if edge vertices are from the\n  // different sets. In this case joint those sets together. Do this until you find\n  // an edge where to edge vertices are already in one set. This means that current\n  // edge will create a cycle.\n  let cycleFound = false;\n  /** @param {GraphEdge} graphEdge */\n  graph.getAllEdges().forEach((graphEdge) => {\n    if (disjointSet.inSameSet(graphEdge.startVertex, graphEdge.endVertex)) {\n      // Cycle found.\n      cycleFound = true;\n    } else {\n      disjointSet.union(graphEdge.startVertex, graphEdge.endVertex);\n    }\n  });\n\n  return cycleFound;\n}\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.de-DE.md",
    "content": "# Dijkstra-Algorithmus\n\n_Lies dies in anderen Sprachen:_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nDer Dijkstra-Algorithmus ist ein Algorithmus zur Bestimmung der kürzesten Wege zwischen Knoten in einem Graphen, der beispielsweise Straßennetze darstellen kann.\n\nDer Algorithmus existiert in vielen Varianten; die ursprüngliche Version von Dijkstra fand den kürzesten Weg zwischen zwei Knoten, aber eine gebräuchlichere Variante fixiert einen einzelnen Knoten als „Quellknoten“ und findet die kürzesten Wege von dieser Quelle zu allen anderen Knoten im Graphen. Das Ergebnis ist ein sogenannter „kürzester-Wege-Baum“ (Shortest-Path Tree).\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nDer Dijkstra-Algorithmus findet den kürzesten Weg zwischen `a` und `b`.\nEr wählt den unbesuchten Knoten mit der kleinsten aktuellen Entfernung,\nberechnet die Distanzen zu jedem unbesuchten Nachbarn über diesen Knoten\nund aktualisiert die Entfernung des Nachbarn, wenn sie kleiner ist.\nNachdem alle Nachbarn überprüft wurden, wird der Knoten als besucht markiert (rot dargestellt).\n\n## Praktische Anwendungen des Dijkstra-Algorithmus\n\n- GPS- und Navigationssysteme\n- Optimierung von Routen im öffentlichen Verkehr und im Flugverkehr\n- Internet-Routing (OSPF-, IS-IS-Protokolle)\n- Optimierung von Netzwerkverkehr und Latenzzeiten\n- Pfadsuche in Computerspielen (kürzester Weg auf Karten)\n- Routenoptimierung in Logistik und Lieferketten\n- Planung von Transport- und Versorgungsnetzen\n\n## Schritt-für-Schritt-Beispiel des Dijkstra-Algorithmus\n\nNehmen wir an, wir haben einen gewichteten Graphen, bei dem jede Kante eine Distanz zwischen Knoten hat.\nZum Beispiel beträgt die Entfernung zwischen Knoten `A` und `B` `7 Meter` (oder kurz `7m`).\n\nDer Algorithmus verwendet eine [Prioritätswarteschlange](../../../data-structures/priority-queue/),\num immer den nächsten unbesuchten Knoten mit der kleinsten Entfernung vom Startknoten zu entnehmen.\n\nDer Startknoten hat per Definition eine Entfernung von `0m` zu sich selbst.\nWir beginnen also mit diesem Knoten – er ist der einzige in der Prioritätswarteschlange zu Beginn.\n\nDie restlichen Knoten werden während der Graphdurchquerung (beim Besuchen der Nachbarn) später hinzugefügt.\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\nJeder Nachbar des aus der Warteschlange entnommenen Knotens wird überprüft, um die Entfernung vom Startpunkt zu berechnen.\nZum Beispiel: Die Entfernung von `A` nach `B` beträgt `0m + 7m = 7m`.\n\nJedes Mal, wenn wir einen neuen, noch nicht gesehenen Nachbarn besuchen, fügen wir ihn der Prioritätswarteschlange hinzu, wobei die Priorität die Distanz zum Startknoten ist.\n\nDer Knoten `B` wird mit der Priorität 7m in die Warteschlange eingefügt, um später besucht zu werden.\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\nAls Nächstes besuchen wir den Nachbarn `C` von `A`.\nDie Entfernung vom Startknoten `A` zu `C` beträgt `0m + 9m = 9m`.\n\nDer Knoten `C` wird ebenfalls in die Prioritätswarteschlange eingefügt.\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\nDasselbe gilt für den Knoten `F`.\nDie aktuelle Entfernung von `A` zu `F` ist `0m + 14m = 14m`.\n\n`F` wird in die Warteschlange eingefügt, um später besucht zu werden.\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\nNachdem alle Nachbarn des aktuellen Knotens überprüft wurden, wird dieser Knoten zur `visited`-Menge hinzugefügt.\nSolche Knoten werden in den nächsten Schritten nicht erneut besucht.\n\nNun entnehmen wir aus der Prioritätswarteschlange den nächsten Knoten mit der kürzesten Distanz zur Quelle und beginnen, seine Nachbarn zu besuchen.\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\nWenn der Knoten, den wir besuchen (in diesem Fall `C`), bereits in der Warteschlange ist,\nbedeutet das, dass die Distanz zu ihm bereits von einem anderen Pfad (`A → C`) berechnet wurde.\nWenn die aktuelle Distanz (über `A → B → C`) kürzer ist, aktualisieren wir den Wert in der Warteschlange.\nIst sie länger, bleibt sie unverändert.\n\nBeim Besuch von `C` über `B` (`A → B → C`) beträgt die Distanz `7m + 10m = 17m`.\nDies ist länger als die bereits gespeicherte Distanz `9m` für `A → C`.\nDaher ignorieren wir diesen längeren Pfad.\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\nWir besuchen einen weiteren Nachbarn von `B`, nämlich `D`.\nDie Entfernung zu `D` beträgt `7m + 15m = 22m`.\nDa `D` noch nicht besucht wurde und nicht in der Warteschlange ist, fügen wir ihn mit der Priorität `22m` hinzu.\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\nAn diesem Punkt wurden alle Nachbarn von `B` besucht, daher wird `B` zur `visited`-Menge hinzugefügt.\nAls Nächstes entnehmen wir aus der Warteschlange den Knoten, der dem Ursprung am nächsten ist.\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\nWir besuchen die unbesuchten Nachbarn von `C`.\nDie Distanz zu `F` über `C` (`A → C → F`) beträgt `9m + 2m = 11m`.\nDies ist kürzer als der bisher gespeicherte Weg `A → F` von `14m`.\nIn diesem Fall aktualisieren wir die Distanz zu `F` auf `11m` und passen ihre Priorität in der Warteschlange an.\nWir haben einen kürzeren Weg zu `F` gefunden.\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\nDasselbe gilt für `D`.\nWir haben einen kürzeren Pfad zu `D` gefunden – der Weg `A → C → D` ist kürzer als `A → B → D`.\nDie Distanz wird von `22m` auf `20m` aktualisiert.\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\nAlle Nachbarn von `C` wurden besucht, daher fügen wir `C` zur `visited`-Menge hinzu.\nWir entnehmen den nächsten Knoten aus der Warteschlange, der `F` ist.\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\nWir notieren die Distanz zu `E` als `11m + 9m = 20m`.\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\nWir fügen `F` zur `visited`-Menge hinzu und entnehmen den nächsten Knoten `D`.\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\nDie Distanz zu `E` über `D` ist `20m + 6m = 26m`.\nDas ist länger als die bereits berechnete Distanz von `20m` über `F`.\nDaher verwerfen wir diesen längeren Weg.\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\nDer Knoten `D` ist jetzt besucht.\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\nAuch der Knoten `E` wurde besucht.\nDie Durchquerung des Graphen ist abgeschlossen.\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\nNun kennen wir die kürzesten Distanzen von jedem Knoten ausgehend vom Startknoten `A`.\n\nIn der Praxis speichert man während der Berechnungen zusätzlich die `previousVertices` (vorherige Knoten),\num die genaue Reihenfolge der Knoten im kürzesten Pfad rekonstruieren zu können.\n\nZum Beispiel ist der kürzeste Pfad von `A` nach `E`: `A → C → F → E`.\n\n## Beispielimplementierung\n\n- [dijkstra.js](./dijkstra.js)\n\n## Quellen\n\n- [Wikipedia](https://de.wikipedia.org/wiki/Dijkstra-Algorithmus)\n- [YouTube – Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube – Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.es-ES.md",
    "content": "# Algoritmo de Dijkstra\n\n_Lee esto en otros idiomas:_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nEl algoritmo de Dijkstra es un algoritmo para encontrar los caminos más cortos entre nodos en un grafo, que puede representar, por ejemplo, redes de carreteras.\n\nEl algoritmo existe en muchas variantes; la versión original de Dijkstra encontraba el camino más corto entre dos nodos, pero una variante más común fija un solo nodo como el \"nodo fuente\" y encuentra los caminos más cortos desde la fuente hacia todos los demás nodos del grafo, produciendo un árbol de caminos más cortos.\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nEl algoritmo de Dijkstra busca el camino más corto entre `a` y `b`.\nSelecciona el vértice no visitado con la menor distancia, calcula la distancia a través de él hacia cada vecino no visitado, y actualiza la distancia del vecino si es menor. Marca el vértice como visitado (en rojo) cuando se han procesado todos sus vecinos.\n\n## Aplicaciones prácticas del algoritmo de Dijkstra\n\n- Sistemas GPS / navegación\n- Optimización de rutas de transporte público y aerolíneas\n- Enrutamiento de Internet (protocolos OSPF, IS-IS)\n- Optimización del tráfico y la latencia en redes\n- Búsqueda de caminos en videojuegos (camino más corto en mapas)\n- Optimización de rutas de logística y entrega\n- Diseño de redes de transporte y cadenas de suministro\n\n## Ejemplo paso a paso del algoritmo de Dijkstra\n\nSupongamos que tenemos un grafo ponderado de nodos, donde cada arista tiene un valor de distancia entre los nodos. Por ejemplo, la distancia entre el nodo `A` y el nodo `B` es de `7 metros` (o simplemente `7m` para abreviar).\n\nEl algoritmo utiliza una [cola de prioridad](../../../data-structures/priority-queue/) para obtener siempre el siguiente vértice no visitado con la menor distancia desde el nodo de origen.\n\nEl nodo inicial, por definición, tiene una distancia de `0m` desde sí mismo. Así que comenzamos con él — el único nodo en la cola de prioridad al inicio.\n\nEl resto de los nodos se agregará a la cola de prioridad más tarde, durante la exploración del grafo (al visitar los vecinos).\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\nCada vecino del nodo extraído de la cola se recorre para calcular la distancia desde el origen.\nPor ejemplo, la distancia de `A` a `B` es `0m + 7m = 7m`.\n\nCada vez que visitamos un vecino aún no visto, lo agregamos a la cola de prioridad, donde la prioridad es la distancia al nodo vecino desde el origen.\n\nEl nodo `B` se agrega a la cola de prioridad mínima para ser recorrido más adelante.\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\nVisitamos el siguiente vecino `C` del nodo `A`.\nLa distancia desde el nodo de origen `A` hasta `C` es `0m + 9m = 9m`.\n\nEl nodo `C` se agrega a la cola de prioridad mínima para recorrerlo más tarde.\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\nLo mismo ocurre con el nodo `F`.\nLa distancia actual de `A` a `F` es `0m + 14m = 14m`.\n\nEl nodo `F` se agrega a la cola de prioridad mínima para ser recorrido más adelante.\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\nUna vez que se han revisado todos los vecinos del nodo actual, este se agrega al conjunto `visited`. No queremos volver a visitar estos nodos más adelante.\n\nAhora extraemos de la cola el siguiente nodo más cercano al origen (el de menor distancia) y comenzamos a visitar sus vecinos.\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\nSi el nodo que estamos visitando (en este caso, `C`) ya está en la cola, significa que ya habíamos calculado la distancia hacia él, pero desde otro camino (`A → C`).\nSi la distancia actual (desde el camino `A → B → C`) es menor que la calculada antes, actualizamos la distancia (en la cola de prioridad) con la más corta, ya que buscamos los caminos más cortos.\nSi la distancia es mayor, la dejamos como está.\n\nAl visitar el nodo `C` a través de `B` (camino `A → B → C`), vemos que la distancia sería `7m + 10m = 17m`.\nEsto es más largo que la distancia ya registrada de `9m` para el camino `A → C`. En estos casos, simplemente ignoramos la distancia más larga.\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\nVisitamos otro vecino de `B`, que es `D`.\nLa distancia hacia `D` es `7m + 15m = 22m`.\nComo aún no hemos visitado `D` y no está en la cola de prioridad, la agregamos con una prioridad (distancia) de `22m`.\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\nEn este punto, todos los vecinos de `B` han sido recorridos, así que agregamos `B` al conjunto `visited`.\nLuego extraemos el nodo más cercano al origen desde la cola de prioridad.\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\nRecorremos los vecinos no visitados del nodo `C`.\nLa distancia hacia `F` a través de `C` (camino `A → C → F`) es `9m + 2m = 11m`.\nEsto es más corto que el camino anterior `A → F` de `14m`.\nEn este caso, actualizamos la distancia de `F` a `11m` y su prioridad en la cola. Hemos encontrado un camino más corto hacia `F`.\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\nLo mismo ocurre con `D`.\nHemos encontrado un camino más corto hacia `D`, donde `A → C → D` es más corto que `A → B → D`.\nActualizamos la distancia de `22m` a `20m`.\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\nTodos los vecinos de `C` han sido recorridos, así que podemos agregar `C` al conjunto `visited`.\nExtraemos de la cola el siguiente nodo más cercano, que es `F`.\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\nRegistramos la distancia hacia `E` como `11m + 9m = 20m`.\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\nAgregamos el nodo `F` al conjunto `visited` y extraemos el siguiente nodo más cercano, `D`.\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\nLa distancia hacia `E` a través de `D` es `20m + 6m = 26m`.\nEsto es más largo que la distancia ya calculada hacia `E` desde `F`, que es `20m`.\nPodemos descartar la distancia más larga.\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\nEl nodo `D` ahora está visitado.\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\nEl nodo `E` también ha sido visitado.\nHemos terminado de recorrer el grafo.\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\nAhora conocemos las distancias más cortas desde el nodo inicial `A` hacia cada nodo.\n\nEn la práctica, durante el cálculo de distancias también registramos los `previousVertices` (vértices anteriores) para poder mostrar la secuencia exacta de nodos que forman el camino más corto.\n\nPor ejemplo, el camino más corto de `A` a `E` es `A → C → F → E`.\n\n## Ejemplo de implementación\n\n- [dijkstra.js](./dijkstra.js)\n\n## Referencias\n\n- [Wikipedia](https://es.wikipedia.org/wiki/Algoritmo_de_Dijkstra)\n- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.fr-FR.md",
    "content": "# Algorithme de Dijkstra\n\n_Lire ceci dans d’autres langues :_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nL’algorithme de Dijkstra est un algorithme permettant de trouver les plus courts chemins entre des nœuds dans un graphe, pouvant représenter, par exemple, un réseau routier.\n\nIl existe plusieurs variantes de cet algorithme. La version originale de Dijkstra trouvait le plus court chemin entre deux nœuds, mais la version la plus courante fixe un seul nœud comme « nœud source » et calcule les plus courts chemins de cette source vers tous les autres nœuds du graphe, produisant ainsi un arbre des plus courts chemins.\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nL’algorithme de Dijkstra trouve le plus court chemin entre `a` et `b`.\nIl sélectionne le sommet non visité avec la plus petite distance, calcule la distance à travers ce sommet vers chacun de ses voisins non visités, et met à jour la distance du voisin si celle-ci est plus courte.\nLe sommet est ensuite marqué comme visité (en rouge) lorsque tous ses voisins ont été traités.\n\n## Applications pratiques de l’algorithme de Dijkstra\n\n- Systèmes GPS / navigation\n- Optimisation des itinéraires de transport public et d’avions\n- Routage Internet (protocoles OSPF, IS-IS)\n- Optimisation du trafic et de la latence réseau\n- Recherche de chemin dans les jeux vidéo (chemin le plus court sur une carte)\n- Optimisation des itinéraires de livraison et de logistique\n- Conception de réseaux de transport et de chaînes d’approvisionnement\n\n## Exemple pas à pas de l’algorithme de Dijkstra\n\nSupposons que nous ayons un graphe pondéré de nœuds, où chaque arête possède une distance entre deux nœuds.\nPar exemple, la distance entre le nœud `A` et le nœud `B` est de `7 mètres` (ou simplement `7m`).\n\nL’algorithme utilise une [file de priorité](../../../data-structures/priority-queue/) pour toujours extraire le prochain sommet non visité ayant la plus petite distance depuis le nœud d’origine.\n\nLe nœud de départ, par définition, a une distance de `0m` depuis lui-même.\nNous commençons donc avec ce nœud, le seul présent dans la file de priorité au départ.\n\nLes autres nœuds seront ajoutés à la file de priorité plus tard, pendant la traversée du graphe (en visitant les voisins).\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\nChaque voisin du nœud extrait de la file est parcouru afin de calculer la distance à partir du nœud d’origine.\nPar exemple, la distance de `A` à `B` est `0m + 7m = 7m`.\n\nChaque fois qu’un voisin encore non visité est découvert, il est ajouté à la file de priorité, la priorité correspondant à la distance depuis le nœud d’origine.\n\nLe nœud `B` est ajouté à la file de priorité minimale pour être traité plus tard.\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\nNous visitons le voisin suivant, `C`, du nœud `A`.\nLa distance depuis le nœud d’origine `A` vers `C` est `0m + 9m = 9m`.\n\nLe nœud `C` est ajouté à la file de priorité minimale pour être parcouru ultérieurement.\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\nMême chose pour le nœud `F`.\nLa distance actuelle de `A` à `F` est `0m + 14m = 14m`.\n\nLe nœud `F` est ajouté à la file de priorité minimale pour être visité plus tard.\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\nUne fois que tous les voisins du nœud actuel ont été examinés, ce nœud est ajouté à l’ensemble `visited`.\nNous ne souhaitons plus revisiter ces nœuds lors des prochaines itérations.\n\nNous extrayons maintenant de la file le nœud le plus proche de la source (celui ayant la plus courte distance) et commençons à visiter ses voisins.\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\nSi le nœud que nous visitons (dans ce cas, `C`) est déjà présent dans la file, cela signifie que sa distance a déjà été calculée via un autre chemin (`A → C`).\nSi la nouvelle distance (depuis le chemin `A → B → C`) est plus courte, nous mettons à jour la distance dans la file de priorité.\nSi elle est plus longue, nous la laissons telle quelle.\n\nEn visitant le nœud `C` via `B` (chemin `A → B → C`), nous trouvons que la distance est `7m + 10m = 17m`.\nCeci est plus long que la distance enregistrée de `9m` pour le chemin `A → C`.\nDans ce cas, nous ignorons simplement cette distance plus longue.\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\nNous visitons un autre voisin de `B`, à savoir `D`.\nLa distance vers `D` est `7m + 15m = 22m`.\nComme `D` n’a pas encore été visité et n’est pas dans la file, nous l’ajoutons avec une priorité (distance) de `22m`.\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\nÀ ce stade, tous les voisins de `B` ont été parcourus, donc nous ajoutons `B` à l’ensemble `visited`.\nEnsuite, nous extrayons de la file le nœud le plus proche du nœud d’origine.\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\nNous parcourons les voisins non visités du nœud `C`.\nLa distance vers `F` via `C` (chemin `A → C → F`) est `9m + 2m = 11m`.\nC’est plus court que la distance précédemment enregistrée de `14m` pour le chemin `A → F`.\nNous mettons donc à jour la distance de `F` à `11m` et ajustons sa priorité dans la file.\nNous venons de trouver un chemin plus court vers `F`.\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\nMême chose pour `D`.\nNous avons trouvé un chemin plus court vers `D` : `A → C → D` est plus court que `A → B → D`.\nNous mettons à jour la distance de `22m` à `20m`.\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\nTous les voisins de `C` ont été parcourus, donc nous pouvons ajouter `C` à l’ensemble `visited`.\nNous extrayons maintenant de la file le prochain nœud le plus proche, `F`.\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\nNous enregistrons la distance vers `E` comme `11m + 9m = 20m`.\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\nNous ajoutons `F` à l’ensemble `visited` et extrayons ensuite `D`, le prochain nœud le plus proche.\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\nLa distance vers `E` via `D` est `20m + 6m = 26m`.\nC’est plus long que la distance déjà calculée depuis `F` (`20m`).\nNous pouvons donc ignorer cette distance plus longue.\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\nLe nœud `D` est maintenant visité.\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\nLe nœud `E` est maintenant visité également.\nLa traversée du graphe est terminée.\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\nNous connaissons maintenant les distances les plus courtes vers chaque nœud depuis le nœud de départ `A`.\n\nEn pratique, pendant le calcul des distances, on enregistre également les `previousVertices` (nœuds précédents) pour pouvoir reconstruire la séquence exacte des nœuds qui forment le chemin le plus court.\n\nPar exemple, le chemin le plus court de `A` à `E` est `A → C → F → E`.\n\n## Exemple d’implémentation\n\n- [dijkstra.js](./dijkstra.js)\n\n## Références\n\n- [Wikipédia](https://fr.wikipedia.org/wiki/Algorithme_de_Dijkstra)\n- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.he-IL.md",
    "content": "# אלגוריתם דייקסטרה (Dijkstra's Algorithm)\n\n_קרא בשפות אחרות:_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nאלגוריתם דייקסטרה הוא אלגוריתם למציאת המסלולים הקצרים ביותר בין צמתים בגרף, שיכול לייצג למשל רשת כבישים.\n\nלאלגוריתם יש מספר גרסאות; הגרסה המקורית של דייקסטרה מצאה את המסלול הקצר ביותר בין שני צמתים, אך גרסה נפוצה יותר קובעת צומת אחד כ\"צומת מקור\" ומוצאת את המסלולים הקצרים ביותר ממנו לכל שאר הצמתים בגרף, וכך נוצרת עץ מסלולים קצרים (Shortest-Path Tree).\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nאלגוריתם דייקסטרה למציאת המסלול הקצר ביותר בין `a` ל־`b`.\nהוא בוחר את הצומת שלא ביקרו בו שעד כה יש לו את המרחק הקטן ביותר,\nמחשב את המרחק דרכו לכל שכן שלא ביקרו בו,\nומעדכן את המרחק אם נמצא מסלול קצר יותר.\nכאשר מסיימים לבדוק את כל השכנים, מסמנים את הצומת כ\"ביקור הושלם\" (אדום).\n\n## שימושים מעשיים של אלגוריתם דייקסטרה\n\n- מערכות GPS / ניווט\n- אופטימיזציה של מסלולי תחבורה ציבורית וטיסות\n- ניתוב באינטרנט (פרוטוקולים OSPF, IS-IS)\n- אופטימיזציה של תעבורת רשת וזמני השהיה\n- חיפוש מסלולים במשחקים (המסלול הקצר ביותר במפה)\n- אופטימיזציה של מסלולי משלוחים ולוגיסטיקה\n- תכנון רשתות תחבורה ושרשראות אספקה\n\n## דוגמה שלב-אחר-שלב לאלגוריתם דייקסטרה\n\nנניח שיש לנו גרף משוקלל של צמתים, שבו לכל קשת יש ערך מרחק בין צמתים.\nלדוגמה, המרחק בין הצומת `A` לצומת `B` הוא `7 מטרים` (או בקיצור `7m`).\n\nהאלגוריתם משתמש ב[תור עדיפויות](../../../data-structures/priority-queue/) כדי תמיד לבחור את הצומת שלא ביקרו בו עם המרחק הקטן ביותר מהצומת ההתחלתי.\n\nצומת ההתחלה, על פי ההגדרה, נמצא במרחק `0m` מעצמו.\nלכן מתחילים ממנו — הצומת היחיד בתור העדיפויות בתחילת התהליך.\n\nשאר הצמתים יתווספו לתור במהלך המעבר בגרף (בעת ביקור בשכנים).\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\nכל שכן של הצומת שנשלף מהתור נבדק כדי לחשב את המרחק אליו מהמקור.\nלדוגמה, המרחק מ־`A` ל־`B` הוא `0m + 7m = 7m`.\n\nבכל פעם שמבקרים שכן חדש שטרם נבדק, מוסיפים אותו לתור העדיפויות,\nכאשר העדיפות נקבעת לפי המרחק מהמקור.\n\nהצומת `B` נוסף לתור העדיפויות המינימלי כדי לעבור עליו מאוחר יותר.\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\nמבקרים את השכן הבא של `A`, שהוא `C`.\nהמרחק מ־`A` ל־`C` הוא `0m + 9m = 9m`.\n\nהצומת `C` נוסף גם הוא לתור העדיפויות.\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\nכנ\"ל לגבי הצומת `F`.\nהמרחק הנוכחי מ־`A` ל־`F` הוא `0m + 14m = 14m`.\n\n`F` נוסף לתור כדי לעבור עליו בהמשך.\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\nלאחר שכל השכנים של הצומת הנוכחי נבדקו, מוסיפים אותו לקבוצת `visited`.\nאין צורך לבקר בו שוב.\n\nכעת נשלוף מהתור את הצומת הקרוב ביותר למקור (בעל המרחק הקצר ביותר)\nונתחיל לבקר את שכניו.\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\nאם הצומת שבו אנו מבקרים (למשל `C`) כבר נמצא בתור,\nהמשמעות היא שכבר חישבנו את המרחק אליו, אבל ממסלול אחר (`A → C`).\nאם המרחק הנוכחי (דרך המסלול `A → B → C`) קצר יותר, נעדכן אותו;\nאם ארוך יותר — נשאיר אותו כפי שהוא.\n\nלדוגמה, בעת ביקור ב־`C` דרך `B` (`A → B → C`), המרחק הוא `7m + 10m = 17m`.\nזה ארוך יותר מהמרחק שכבר נרשם (`9m`), ולכן אין עדכון.\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\nמבקרים שכן נוסף של `B`, שהוא `D`.\nהמרחק ל־`D` הוא `7m + 15m = 22m`.\nמכיוון שטרם ביקרנו ב־`D` והוא אינו בתור, נוסיף אותו עם עדיפות (מרחק) של `22m`.\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\nבשלב זה כל שכניו של `B` נבדקו, ולכן נוסיף את `B` לקבוצת `visited`.\nלאחר מכן נשלוף את הצומת הקרוב ביותר למקור מהתור.\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\nמבקרים את השכנים הלא-מבוקרים של `C`.\nהמרחק ל־`F` דרך `C` (המסלול `A → C → F`) הוא `9m + 2m = 11m`.\nזה קצר יותר מהמרחק שנרשם קודם (`14m` ל־`A → F`).\nלכן נעדכן את המרחק של `F` ל־`11m` ואת העדיפות שלו בתור.\nמצאנו מסלול קצר יותר ל־`F`.\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\nאותו הדבר עבור `D`.\nמצאנו מסלול קצר יותר — `A → C → D` קצר מ־`A → B → D`.\nנעדכן את המרחק מ־`22m` ל־`20m`.\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\nכל שכניו של `C` נבדקו, ולכן נוסיף את `C` ל־`visited`.\nנשלוף מהתור את הצומת הקרוב ביותר הבא — `F`.\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\nנרשום את המרחק ל־`E` כ־`11m + 9m = 20m`.\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\nנוסיף את `F` לקבוצת `visited`, ונשלוף את הצומת הקרוב הבא — `D`.\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\nהמרחק ל־`E` דרך `D` הוא `20m + 6m = 26m`.\nזה ארוך יותר מהמרחק שכבר חושב (`20m` דרך `F`), ולכן נתעלם ממנו.\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\nהצומת `D` כעת סומן כ\"ביקור הושלם\".\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\nהצומת `E` גם סומן כ\"ביקור הושלם\".\nסיימנו את המעבר בגרף.\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\nכעת אנו יודעים את המרחקים הקצרים ביותר מכל צומת לנקודת ההתחלה `A`.\n\nבפועל, במהלך חישוב המרחקים שומרים גם את ה־`previousVertices` (הצמתים הקודמים)\nכדי שנוכל לשחזר את הרצף המדויק של הצמתים שמרכיבים את המסלול הקצר ביותר.\n\nלדוגמה, המסלול הקצר מ־`A` ל־`E` הוא `A → C → F → E`.\n\n## דוגמת מימוש\n\n- [dijkstra.js](./dijkstra.js)\n\n## מקורות\n\n- [ויקיפדיה](https://he.wikipedia.org/wiki/אלגוריתם_דייקסטרה)\n- [YouTube – Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube – Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.ja-JP.md",
    "content": "# ダイクストラ法 (Dijkstra's Algorithm)\n\n_他の言語で読む:_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nダイクストラ法は、グラフ内のノード間の最短経路を見つけるためのアルゴリズムです。\n例えば道路網などを表すことができます。\n\nこのアルゴリズムにはいくつかのバリエーションがあります。\nダイクストラの元々の手法は、2つのノード間の最短経路を求めるものでしたが、\nより一般的なバージョンでは、1つのノードを「始点（ソース）」として固定し、\nその始点から他のすべてのノードまでの最短経路を求め、最短経路木（shortest-path tree）を生成します。\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\n`a` から `b` への最短経路を見つけるダイクストラ法。\n訪問していないノードの中で最も距離の短いノードを選び、\nそのノードを経由して未訪問の隣接ノードへの距離を計算し、\nもし短ければその距離を更新します。\nすべての隣接ノードを処理したら、そのノードを訪問済み（赤色）としてマークします。\n\n## ダイクストラ法の実用例\n\n- GPS / ナビゲーションシステム\n- 公共交通機関や航空路線の最適化\n- インターネットルーティング（OSPF、IS-IS プロトコル）\n- ネットワークトラフィックとレイテンシーの最適化\n- ゲームにおける経路探索（マップ上の最短経路）\n- 物流および配送ルートの最適化\n- サプライチェーンや交通ネットワーク設計\n\n## ダイクストラ法のステップごとの例\n\n重み付きグラフがあり、各辺にはノード間の距離が設定されています。\nたとえば、ノード `A` とノード `B` の距離が `7m` であるとします。\n\nこのアルゴリズムは、[優先度付きキュー](../../../data-structures/priority-queue/)を使用し、\n常に始点から最も近い未訪問ノードを取り出します。\n\n始点ノードは自分自身からの距離が `0m` なので、\n最初にキューに入っているのはこのノードだけです。\n\n他のノードは、グラフ探索中（隣接ノードを訪問する際）に後でキューに追加されます。\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\nキューから取り出したノードの各隣接ノードについて、始点からの距離を計算します。\nたとえば、`A` から `B` までの距離は `0m + 7m = 7m` です。\n\n初めて訪れる隣接ノードは、始点からの距離を優先度としてキューに追加されます。\n\nノード `B` は、後で探索するために最小優先度キューに追加されます。\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\n次に、ノード `A` のもう一つの隣接ノード `C` を訪問します。\n始点 `A` から `C` までの距離は `0m + 9m = 9m` です。\n\nノード `C` も最小優先度キューに追加されます。\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\n同様に、ノード `F` の場合、始点 `A` からの距離は `0m + 14m = 14m` です。\n\nノード `F` も後で探索するためにキューに追加します。\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\n現在のノードのすべての隣接ノードを確認した後、\nそのノードを `visited` セットに追加します。\nこのノードは今後再訪しません。\n\n次に、始点から最も近いノードをキューから取り出し、\nその隣接ノードを訪問します。\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\n訪問中のノード（この場合は `C`）がすでにキューに存在する場合、\nそれは別の経路（`A → C`）からすでに距離を計算したことを意味します。\nもし今回の経路（`A → B → C`）を通る距離が短ければ更新し、\n長ければそのままにします。\n\nたとえば、`B` 経由で `C` に行くと (`A → B → C`)、距離は `7m + 10m = 17m` です。\nこれは既に記録されている距離 `9m` より長いので、更新しません。\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\n次に、`B` のもう一つの隣接ノード `D` を訪問します。\n距離は `7m + 15m = 22m` です。\n`D` はまだ訪問されておらず、キューにもないため、\n距離 `22m` の優先度でキューに追加します。\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\nこの時点で `B` のすべての隣接ノードを訪問したので、`B` を `visited` に追加します。\n次に、始点に最も近いノードをキューから取り出します。\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\nノード `C` の未訪問の隣接ノードを探索します。\n経路 `A → C → F` を通る `F` までの距離は `9m + 2m = 11m` です。\nこれは以前の `A → F` の距離 `14m` より短いので、\n`F` の距離を `11m` に更新し、キューの優先度を変更します。\nこれでより短い経路が見つかりました。\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\n`D` についても同様です。\n経路 `A → C → D` は `A → B → D` より短いため、\n距離を `22m` から `20m` に更新します。\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\n`C` のすべての隣接ノードを訪問したので、`C` を `visited` に追加し、\n次に最も近いノード `F` をキューから取り出します。\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\n`E` への距離を `11m + 9m = 20m` として記録します。\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\n`F` を `visited` に追加し、次に最も近い `D` を取り出します。\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\n`D` 経由で `E` に行く距離は `20m + 6m = 26m` です。\nこれはすでに `F` 経由の距離 `20m` より長いため、無視します。\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\nノード `D` が訪問されました。\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\nノード `E` も訪問されました。\nグラフ探索が完了しました。\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\nこれで、始点ノード `A` から各ノードへの最短距離がわかりました。\n\n実際には、距離計算の際に各ノードの `previousVertices`（直前のノード）も記録し、\n最短経路の正確な経路を再構築できるようにします。\n\n例えば、`A` から `E` への最短経路は `A → C → F → E` です。\n\n## 実装例\n\n- [dijkstra.js](./dijkstra.js)\n\n## 参考文献\n\n- [ウィキペディア](https://ja.wikipedia.org/wiki/ダイクストラ法)\n- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.ko-KR.md",
    "content": "# 다익스트라 알고리즘 (Dijkstra's Algorithm)\n\n_다른 언어로 읽기:_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\n다익스트라 알고리즘은 그래프의 노드 간 최단 경로를 찾는 알고리즘으로, 예를 들어 도로망을 표현할 수 있습니다.\n\n이 알고리즘에는 여러 변형이 있습니다. 다익스트라의 원래 알고리즘은 두 노드 간의 최단 경로를 찾았지만, 더 일반적인 변형은 하나의 노드를 \"출발점(source)\"으로 고정하고 그 노드로부터 다른 모든 노드까지의 최단 경로를 찾습니다. 이 과정을 통해 최단 경로 트리(shortest-path tree)가 만들어집니다.\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\n다익스트라 알고리즘은 `a`에서 `b`로 가는 최단 경로를 찾습니다.\n아직 방문하지 않은 노드 중 가장 짧은 거리를 가진 노드를 선택하고,\n그 노드를 통해 이웃 노드로 가는 거리를 계산하여\n더 짧은 경로가 있으면 업데이트합니다.\n모든 이웃을 확인하면 해당 노드를 방문 완료(빨간색으로 표시)로 처리합니다.\n\n## 다익스트라 알고리즘의 실제 활용 사례\n\n- GPS / 내비게이션 시스템\n- 대중교통 및 항공 노선 최적화\n- 인터넷 라우팅 (OSPF, IS-IS 프로토콜)\n- 네트워크 트래픽 및 지연 시간 최적화\n- 게임에서의 경로 탐색 (지도상의 최단 경로)\n- 물류 및 배송 경로 최적화\n- 공급망 및 교통 네트워크 설계\n\n## 단계별 다익스트라 알고리즘 예제\n\n가중치가 있는 그래프가 있다고 가정합시다. 각 간선에는 노드 간의 거리 값이 있습니다. 예를 들어, 노드 `A`와 `B` 사이의 거리가 `7m`라고 하겠습니다.\n\n이 알고리즘은 항상 출발 노드로부터 가장 짧은 거리를 가진 방문하지 않은 노드를 꺼내기 위해 [우선순위 큐](../../../data-structures/priority-queue/)를 사용합니다.\n\n출발 노드는 자기 자신으로부터의 거리가 `0m`이므로, 우선순위 큐에는 처음에 이 노드만 포함되어 있습니다.\n\n다른 노드들은 그래프 탐색 중(이웃 노드를 방문할 때) 나중에 우선순위 큐에 추가됩니다.\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\n큐에서 꺼낸 노드의 각 이웃을 순회하면서 출발 노드로부터의 거리를 계산합니다.\n예를 들어, `A`에서 `B`까지의 거리는 `0m + 7m = 7m`입니다.\n\n아직 방문하지 않은 이웃을 처음 방문하면, 출발 노드로부터의 거리를 우선순위로 하여 우선순위 큐에 추가합니다.\n\n`B` 노드는 나중에 탐색하기 위해 최소 우선순위 큐에 추가됩니다.\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\n다음으로 `A`의 또 다른 이웃 `C`를 방문합니다.\n출발 노드 `A`에서 `C`까지의 거리는 `0m + 9m = 9m`입니다.\n\n`C` 노드는 이후 탐색을 위해 우선순위 큐에 추가됩니다.\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\n`F` 노드도 동일합니다.\n`A`에서 `F`까지의 거리는 `0m + 14m = 14m`입니다.\n\n`F` 노드는 나중에 탐색하기 위해 우선순위 큐에 추가됩니다.\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\n현재 노드의 모든 이웃을 확인한 후에는 이 노드를 `visited` 집합에 추가합니다.\n이후에는 이 노드를 다시 방문하지 않습니다.\n\n이제 큐에서 출발점으로부터 가장 가까운 노드를 꺼내 그 이웃들을 방문합니다.\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\n방문하려는 노드(`C`)가 이미 큐에 있다면, 이전에 다른 경로(`A → C`)를 통해 계산된 거리 정보가 있다는 뜻입니다.\n만약 현재 경로(`A → B → C`)를 통한 거리가 이전 거리보다 짧으면, 큐의 값을 업데이트합니다.\n그렇지 않으면 변경하지 않습니다.\n\n예를 들어 `B`를 통해 `C`를 방문할 때(`A → B → C`), 거리는 `7m + 10m = 17m`입니다.\n이는 이미 기록된 거리 `9m`보다 길기 때문에 업데이트하지 않습니다.\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\n`B`의 또 다른 이웃인 `D`를 방문합니다.\n`D`까지의 거리는 `7m + 15m = 22m`입니다.\n아직 방문하지 않았고 큐에도 없으므로, 우선순위 `22m`으로 큐에 추가합니다.\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\n이 시점에서 `B`의 모든 이웃을 방문했으므로, `B`를 `visited` 집합에 추가합니다.\n이제 큐에서 출발점에 가장 가까운 노드를 꺼냅니다.\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\n`C`의 방문하지 않은 이웃들을 탐색합니다.\n`C`를 통해 `F`로 가는 경로(`A → C → F`)의 거리는 `9m + 2m = 11m`입니다.\n이는 기존의 `A → F` 거리 `14m`보다 짧습니다.\n따라서 `F`의 거리를 `11m`로 업데이트하고 큐의 우선순위를 갱신합니다.\n더 짧은 경로를 찾았습니다.\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\n`D`도 마찬가지입니다.\n`A → C → D` 경로가 `A → B → D`보다 짧으므로, `22m`을 `20m`으로 업데이트합니다.\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\n`C`의 모든 이웃을 방문했으므로 `C`를 `visited`에 추가하고,\n큐에서 다음으로 가까운 노드 `F`를 꺼냅니다.\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\n`E`까지의 거리를 `11m + 9m = 20m`으로 기록합니다.\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\n`F`를 `visited`에 추가하고, 다음으로 가까운 `D`를 꺼냅니다.\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\n`D`를 통해 `E`로 가는 거리는 `20m + 6m = 26m`입니다.\n이는 이미 계산된 `20m`보다 길기 때문에 무시합니다.\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\n`D` 노드가 방문 완료되었습니다.\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\n`E` 노드도 방문 완료되었습니다.\n그래프 탐색이 끝났습니다.\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\n이제 출발 노드 `A`로부터 각 노드까지의 최단 거리를 알 수 있습니다.\n\n실제로는 거리 계산 중 각 노드의 `previousVertices`(이전 노드)를 함께 저장하여\n최단 경로를 복원할 수 있습니다.\n\n예를 들어, `A`에서 `E`로 가는 최단 경로는 `A → C → F → E`입니다.\n\n## 구현 예시\n\n- [dijkstra.js](./dijkstra.js)\n\n## 참고 자료\n\n- [위키백과](https://ko.wikipedia.org/wiki/다익스트라_알고리즘)\n- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.md",
    "content": "# Dijkstra's Algorithm\n\n_Read this in other languages:_\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nDijkstra's algorithm is an algorithm for finding the shortest\npaths between nodes in a graph, which may represent, for example,\nroad networks.\n\nThe algorithm exists in many variants; Dijkstra's original variant\nfound the shortest path between two nodes, but a more common\nvariant fixes a single node as the \"source\" node and finds\nshortest paths from the source to all other nodes in the graph,\nproducing a shortest-path tree.\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nDijkstra's algorithm to find the shortest path between `a` and `b`.\nIt picks the unvisited vertex with the lowest distance,\ncalculates the distance through it to each unvisited neighbor,\nand updates the neighbor's distance if smaller. Mark visited\n(set to red) when done with neighbors.\n\n## Practical applications of Dijkstra's algorithm\n\n- GPS / navigation systems\n- Public transit and airline route optimization\n- Internet routing (OSPF, IS-IS protocols)\n- Network traffic & latency optimization\n- Game pathfinding (shortest path on maps)\n- Logistics & delivery route optimization\n- Supply chain & transportation network design\n\n## Step-by-step Dijkstra's algorithm example\n\nLet's say we have a weighted graph of nodes, where each edge has a distance parameter between nodes. Let's say the distance from node `A` and node `B` is `7 meters` (or just `7m` for brevity), and so on.\n\nThe algorithm uses [Priority Queue](../../../data-structures/priority-queue/) to always pull the next unvisited vertex that has the smallest distance from the origin node.\n\nThe start node, by definition, has a distance of `0m` from itself. So we start from it, the only node in the priority queue.\n\nThe rest of the nodes will be added to the priority queue later during the graph traversal (while visiting the neighbors).\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\nEach neighbor of the pulled (from the queue) node is being traversed to calculate the distance to it from the origin. For example, the distance from `A` to `B` is `0m + 7m = 7m`, and so on.\n\nEvery time we visit a not-yet-seen neighbor, we add it to the priority queue, where the priority is the distance to the neighbor node from the origin node.\n\nThe node `B` is being added to the min priority queue to be traversed later.\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\nVisiting the next neighbor `C` of the node `A`. The distance from the origin node `A` to `C` is `0m + 9m = 9m`.\n\nThe node `C` is being added to the min priority queue to be traversed later.\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\nSame for the node `F`. The current distance to `F` from the origin node `A` is `0m + 14m = 14m`.\n\nThe node `F` is being added to the min priority queue to be traversed later.\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\nOnce all the neighbors of the current node were checked, the current node was added to the `visited` set. We don't want to visit such nodes once again during the upcoming traverses.\n\nNow, let's pull out the next node from the priority queue that is closest to the origin (has a shorter distance). We start visiting its neighbors as well.\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\nIf the node that we're visiting (in this case, the node `C`) is already in the queue, it means we already calculated the distance to it before, but from another node/path (`A → C`). If the current distance to it (from the current neighbor node `A → B → C`) is shorter than the one that was calculated before, we update the distance (in the priority queue) to the shortest one, since we're searching for the shortest paths. If the distance from the current neighbor is actually longer than the one that was already calculated, we leave it like this without updating the `C` node distance in the queue.\n\nWhile visiting the node `C` via `B` (the path `A → B → C`), we see that the distance to it would be `7m + 10m = 17m`. This is actually longer than the already recorded distance of `9m` for the path `A → C`. In such cases, we just ignore the longest distance and don't update the priority (the minimum found distance at the moment from the origin node).\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\nVisiting another neighbor of `B`, which is `D`. The distance to `D` equals `7m + 15m = 22m`. Since we didn't visit `D` yet and it is not in the min priority queue, let's just add it to the queue with a priority (distance) of `22m`.\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\nAt this point, all of the neighbors of `B` were traversed, so we add `B` to the `visited` set. Next, we pull the node that is closest to the origin node from the priority queue.\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\nTraversing the unvisited neighbors of the node `C`. The distance to node `F` via `C` (the path `A → C → F`) is `9m + 2m = 11m`. This is actually shorter than the previously recorded path `A → F` of `14m` length. In such cases, we update the distance to `F` to `11m` and update its priority in the queue from `14m` to `11m`. We've just found a shorter path to `F`.\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\nThe same goes for `D`. We've just found a shorter path to `D`, where `A → C → D` is shorter than `A → B → D`. Updating the distance from `22m` to `20m`.\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\nAll neighbors of `C` were traversed, so we may add `C` to the `visited` set. Pulling the next closest node from the queue, which is `F`.\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\nRecording the distance to `E` as `11m + 9m = 20m`.\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\nAdding the node `F` to the `visited` set, and pulling the next closest node `D` from the queue.\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\nDistance to `E` via `D` is `20m + 6m = 26m`. This is longer than the already calculated distance to `E` from `F`, which is `20m`. We can discard the longer distance.\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\nNode `D` is visited now.\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\nNode `E` is visited now as well. We've finished the graph traversal.\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\nNow we know the shortest distances to each node from the start node `A`.\n\nIn practice, during the distance calculations, we also record the `previousVertices` for each node to be able to show the exact sequence of nodes that form the shortest path.\n\nFor example, the shorter path from `A` to `E` is `A → C → F → E`.\n\n## Implementation example\n\n- [dijkstra.js](./dijkstra.js)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)\n- [On YouTube by Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.uk-UA.md",
    "content": "# Алгоритм Дейкстри\n\n_Читайте іншими мовами:_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nАлгоритм Дейкстри — це алгоритм пошуку найкоротших шляхів між вершинами графа, який може представляти, наприклад, дорожню мережу.\n\nІснує багато варіантів цього алгоритму; оригінальний варіант Дейкстри знаходив найкоротший шлях між двома вершинами, але більш поширений варіант фіксує одну вершину як «джерело» і знаходить найкоротші шляхи від неї до всіх інших вершин графа, утворюючи дерево найкоротших шляхів.\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nАлгоритм Дейкстри для пошуку найкоротшого шляху між `a` та `b`.\nВін вибирає непереглянуту вершину з найменшою відстанню, обчислює відстань через неї до кожного непереглянутого сусіда й оновлює відстань до сусіда, якщо вона менша. Коли всі сусіди опрацьовані — вершина позначається як відвідана (червоним кольором).\n\n## Практичні застосування алгоритму Дейкстри\n\n- GPS / навігаційні системи\n- Оптимізація маршрутів громадського транспорту та авіаліній\n- Інтернет-маршрутизація (протоколи OSPF, IS-IS)\n- Оптимізація мережевого трафіку та затримок\n- Пошук шляху в іграх (найкоротший шлях на карті)\n- Оптимізація маршрутів доставки\n- Проєктування логістичних та транспортних мереж\n\n## Покроковий приклад алгоритму Дейкстри\n\nПрипустімо, ми маємо зважений граф вершин, де кожне ребро має певну довжину. Наприклад, відстань між вершинами `A` і `B` становить `7 метрів` (або просто `7m`).\n\nАлгоритм використовує [чергу з пріоритетом](../../../data-structures/priority-queue/), щоб завжди вибирати наступну непереглянуту вершину з найменшою відстанню від початкової вершини.\n\nПочаткова вершина, за визначенням, має відстань `0m` від самої себе. З неї й починається пошук — вона єдина в черзі на початку.\n\nРешта вершин додаються до черги з пріоритетом пізніше, у процесі обходу графа (під час відвідування сусідів).\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\nКожен сусід витягнутої з черги вершини перевіряється для обчислення відстані до нього від початкової вершини. Наприклад, відстань від `A` до `B` — це `0m + 7m = 7m`.\n\nЩоразу, коли ми відвідуємо нового (ще не баченого) сусіда, ми додаємо його в чергу з пріоритетом, де пріоритет — це відстань до цієї вершини від початкової.\n\nВершину `B` додаємо до мінімальної черги з пріоритетом, щоб відвідати її пізніше.\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\nВідвідуємо наступного сусіда `C` вершини `A`. Відстань від `A` до `C` становить `0m + 9m = 9m`.\n\nДодаємо вершину `C` до мінімальної черги з пріоритетом.\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\nТе саме робимо для вершини `F`. Поточна відстань від `A` до `F` — `0m + 14m = 14m`.\n\nВершину `F` додаємо до черги для подальшого обходу.\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\nКоли всі сусіди поточної вершини перевірені, ми додаємо її до множини `visited`. Такі вершини більше не відвідуємо.\n\nТепер вибираємо з черги наступну вершину, найближчу до початкової, і починаємо відвідувати її сусідів.\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\nЯкщо вершина, яку ми відвідуємо (наприклад, `C`), уже є в черзі, це означає, що відстань до неї вже обчислювалася раніше з іншого шляху (`A → C`). Якщо нова відстань (через інший шлях, наприклад `A → B → C`) менша, ми оновлюємо її в черзі. Якщо більша — залишаємо без змін.\n\nПід час відвідування `C` через `B` (`A → B → C`), відстань дорівнює `7m + 10m = 17m`. Це більше, ніж уже відома `9m` для шляху `A → C`. Тож ми ігноруємо довший шлях.\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\nВідвідуємо іншого сусіда `B` — вершину `D`. Відстань до `D` дорівнює `7m + 15m = 22m`.\nОскільки `D` ще не відвідано і її немає в черзі, додаємо її з пріоритетом `22m`.\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\nТепер усіх сусідів `B` відвідано, тож додаємо `B` до множини `visited`.\nНаступною вибираємо вершину, що найближча до початкової.\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\nВідвідуємо непереглянутих сусідів вершини `C`.\nВідстань до вершини `F` через `C` (`A → C → F`) дорівнює `9m + 2m = 11m`.\nЦе коротше за попередній шлях `A → F` довжиною `14m`.\nТому оновлюємо відстань до `F` — з `14m` до `11m`. Ми щойно знайшли коротший шлях.\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\nТак само для `D`: шлях `A → C → D` коротший за `A → B → D`.\nОновлюємо відстань з `22m` до `20m`.\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\nУсі сусіди `C` пройдені, додаємо її до `visited`.\nДістаємо з черги наступну найближчу вершину — `F`.\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\nЗаписуємо відстань до `E`: `11m + 9m = 20m`.\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\nДодаємо `F` до множини `visited`, далі дістаємо `D`.\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\nВідстань до `E` через `D`: `20m + 6m = 26m`.\nЦе більше, ніж уже обчислені `20m` через `F`, тому ігноруємо довший шлях.\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\nВершину `D` відвідано.\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\nВершину `E` також відвідано. Обхід графа завершено.\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\nТепер ми знаємо найкоротші відстані до кожної вершини від початкової `A`.\n\nНа практиці під час обчислення відстаней також зберігаються `previousVertices` — попередні вершини, щоб можна було відновити повний шлях.\n\nНаприклад, найкоротший шлях від `A` до `E` — це `A → C → F → E`.\n\n## Приклад реалізації\n\n- [dijkstra.js](./dijkstra.js)\n\n## Джерела\n\n- [Вікіпедія](https://uk.wikipedia.org/wiki/Алгоритм_Дейкстри)\n- [Відео на YouTube від Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Відео на YouTube від Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.zh-CN.md",
    "content": "# Dijkstra 算法\n\n_阅读其他语言版本：_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nDijkstra 算法是一种用于在图中查找节点之间最短路径的算法，例如，它可以用于表示道路网络。\n\n该算法有许多变体；Dijkstra 的原始版本用于查找两个节点之间的最短路径，但更常见的变体是将一个节点固定为“源节点”，并计算从该源节点到图中所有其他节点的最短路径，从而生成最短路径树。\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nDijkstra 算法用于查找从 `a` 到 `b` 的最短路径。\n它选择未访问的距离最小的节点，计算通过它到每个未访问邻居的距离，\n如果更短，则更新邻居的距离。\n当该节点的所有邻居都被处理完后，将其标记为已访问（红色）。\n\n## Dijkstra 算法的实际应用\n\n- GPS / 导航系统\n- 公共交通和航线优化\n- 互联网路由（OSPF、IS-IS 协议）\n- 网络流量与延迟优化\n- 游戏路径寻路（地图上的最短路径）\n- 物流与配送路线优化\n- 供应链与交通网络设计\n\n## Dijkstra 算法逐步示例\n\n假设我们有一个带权图，每条边表示节点之间的距离。\n例如，节点 `A` 和节点 `B` 之间的距离是 `7 米`（简称 `7m`）。\n\n算法使用 [优先队列](../../../data-structures/priority-queue/) 来始终提取离起始节点距离最短的未访问节点。\n\n起始节点与自身的距离定义为 `0m`。因此我们从它开始，这是优先队列中的唯一节点。\n\n在遍历图的过程中（访问邻居节点时），其余节点会逐渐被添加到优先队列中。\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\n从队列中取出的节点的每个邻居都会被遍历，以计算从起点到该邻居的距离。\n例如，从 `A` 到 `B` 的距离为 `0m + 7m = 7m`。\n\n每次访问尚未访问的邻居时，将其加入优先队列，优先级为从起点到该节点的距离。\n\n节点 `B` 被加入最小优先队列，以便稍后遍历。\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\n接着访问节点 `A` 的另一个邻居 `C`。\n从起始节点 `A` 到 `C` 的距离为 `0m + 9m = 9m`。\n\n节点 `C` 被加入最小优先队列，等待后续遍历。\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\n同样地，对于节点 `F`，从起始节点 `A` 的当前距离是 `0m + 14m = 14m`。\n\n节点 `F` 被加入最小优先队列，等待后续遍历。\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\n当当前节点的所有邻居都被检查完后，将当前节点添加到 `visited` 集合中。\n在后续遍历中不会再次访问这些节点。\n\n现在，从优先队列中取出离起点最近（距离最短）的节点，开始访问它的邻居。\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\n如果正在访问的节点（此处为 `C`）已经在队列中，\n表示之前通过另一条路径（`A → C`）已计算过其距离。\n如果当前路径（`A → B → C`）的距离更短，则更新距离；\n否则保持原状。\n\n例如，通过 `B` 访问 `C`（路径 `A → B → C`），距离为 `7m + 10m = 17m`。\n这比已记录的 `A → C` 路径的 `9m` 更长，因此忽略。\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\n访问 `B` 的另一个邻居 `D`。\n到 `D` 的距离为 `7m + 15m = 22m`。\n由于 `D` 尚未访问，也不在队列中，因此将其以距离 `22m` 的优先级加入队列。\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\n此时，`B` 的所有邻居都已遍历，因此将 `B` 添加到 `visited` 集合中。\n接着，从优先队列中取出离起始节点最近的节点。\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\n遍历节点 `C` 的未访问邻居。\n通过 `C` 到 `F` 的路径（`A → C → F`）距离为 `9m + 2m = 11m`。\n这比之前记录的路径 `A → F`（`14m`）更短。\n因此，将 `F` 的距离更新为 `11m`，并在队列中调整其优先级。\n我们找到了到 `F` 的更短路径。\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\n对于 `D` 也是如此。\n路径 `A → C → D` 比 `A → B → D` 更短，\n因此将距离从 `22m` 更新为 `20m`。\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\n`C` 的所有邻居都已遍历完，将其加入 `visited`。\n然后从队列中取出下一个最近的节点 `F`。\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\n记录到 `E` 的距离：`11m + 9m = 20m`。\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\n将节点 `F` 添加到 `visited` 集合中，并从队列中取出下一个最近的节点 `D`。\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\n通过 `D` 到 `E` 的距离为 `20m + 6m = 26m`。\n这比通过 `F` 的 `20m` 更长，因此忽略。\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\n节点 `D` 已访问。\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\n节点 `E` 也已访问。\n图的遍历完成。\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\n现在，我们已经知道从起始节点 `A` 到每个节点的最短距离。\n\n在实际应用中，在计算距离的同时，还会记录每个节点的 `previousVertices`（前驱节点），\n以便重建形成最短路径的节点序列。\n\n例如，从 `A` 到 `E` 的最短路径为 `A → C → F → E`。\n\n## 实现示例\n\n- [dijkstra.js](./dijkstra.js)\n\n## 参考资料\n\n- [维基百科](https://zh.wikipedia.org/wiki/Dijkstra算法)\n- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/README.zh-TW.md",
    "content": "# Dijkstra 演算法\n\n_以其他語言閱讀：_\n[_English_](README.md),\n[_한국어_](README.ko-KR.md),\n[_日本語_](README.ja-JP.md),\n[_简体中文_](README.zh-CN.md),\n[_繁體中文_](README.zh-TW.md),\n[_Українська_](README.uk-UA.md),\n[_Español_](README.es-ES.md),\n[_Français_](README.fr-FR.md),\n[_Deutsch_](README.de-DE.md),\n[_עברית_](README.he-IL.md)\n\nDijkstra 演算法是一種用於在圖中尋找節點之間最短路徑的演算法，例如，它可用於表示道路網絡。\n\n該演算法有許多變體；Dijkstra 的原始版本用於尋找兩個節點之間的最短路徑，但更常見的變體是將一個節點固定為「起點（source）」節點，並從該節點計算到圖中所有其他節點的最短路徑，從而生成最短路徑樹（shortest-path tree）。\n\n![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n\nDijkstra 演算法用於尋找從 `a` 到 `b` 的最短路徑。\n它會選擇距離最短且尚未訪問的節點，計算經由該節點到各個未訪問鄰居的距離，\n若該距離更短，則更新鄰居的距離。\n當所有鄰居處理完畢後，將該節點標記為已訪問（紅色）。\n\n## Dijkstra 演算法的實際應用\n\n- GPS / 導航系統\n- 公共交通與航空路線最佳化\n- 網際網路路由（OSPF、IS-IS 協定）\n- 網路流量與延遲最佳化\n- 電玩遊戲中的路徑尋找（地圖上的最短路徑）\n- 物流與配送路線最佳化\n- 供應鏈與交通網路設計\n\n## Dijkstra 演算法逐步範例\n\n假設我們有一個帶權重的圖，每條邊都代表節點之間的距離。\n例如，節點 `A` 與節點 `B` 之間的距離為 `7 公尺`（簡稱 `7m`）。\n\n演算法使用 [優先佇列（Priority Queue）](../../../data-structures/priority-queue/)\n來不斷取出距離起點最近的未訪問節點。\n\n起始節點與自身的距離定義為 `0m`，因此我們從它開始，\n此時它是優先佇列中唯一的節點。\n\n其餘節點會在圖遍歷過程中（訪問鄰居時）逐漸加入佇列。\n\n![Dijkstra step 1](./images/dijkstra-01.png)\n\n從佇列中取出的節點，其每個鄰居都會被檢查，以計算從起點到該鄰居的距離。\n例如，從 `A` 到 `B` 的距離為 `0m + 7m = 7m`。\n\n每當訪問尚未看過的鄰居時，就將其加入優先佇列，\n其優先權為從起點到該鄰居的距離。\n\n節點 `B` 被加入最小優先佇列，以便稍後處理。\n\n![Dijkstra step 2](./images/dijkstra-02.png)\n\n接著訪問節點 `A` 的另一個鄰居 `C`。\n從起點 `A` 到 `C` 的距離為 `0m + 9m = 9m`。\n\n節點 `C` 被加入最小優先佇列，等待後續遍歷。\n\n![Dijkstra step 3](./images/dijkstra-03.png)\n\n同樣地，對於節點 `F`，\n從起點 `A` 到 `F` 的距離為 `0m + 14m = 14m`。\n\n節點 `F` 被加入最小優先佇列，以便稍後處理。\n\n![Dijkstra step 4](./images/dijkstra-04.png)\n\n當目前節點的所有鄰居都被檢查完後，\n將該節點加入 `visited` 集合中。\n之後將不再重新訪問該節點。\n\n接著從佇列中取出距離起點最近的節點，開始訪問它的鄰居。\n\n![Dijkstra step 5](./images/dijkstra-05.png)\n\n若正在訪問的節點（例如 `C`）已存在於佇列中，\n代表先前已經透過另一條路徑（`A → C`）計算過其距離。\n若目前路徑（`A → B → C`）的距離更短，則更新距離；\n若更長，則保持不變。\n\n例如，透過 `B` 訪問 `C`（路徑 `A → B → C`）的距離為 `7m + 10m = 17m`，\n比原先記錄的 `9m` 更長，因此不需更新。\n\n![Dijkstra step 6](./images/dijkstra-06.png)\n\n接著訪問 `B` 的另一個鄰居 `D`。\n到 `D` 的距離為 `7m + 15m = 22m`。\n由於 `D` 尚未訪問，也不在佇列中，因此將其以優先權（距離）`22m` 加入佇列。\n\n![Dijkstra step 7](./images/dijkstra-07.png)\n\n此時 `B` 的所有鄰居都已遍歷完，\n因此將 `B` 加入 `visited` 集合中。\n接著從佇列中取出距離起點最近的節點。\n\n![Dijkstra step 8](./images/dijkstra-08.png)\n\n訪問節點 `C` 的未訪問鄰居。\n經由 `C` 到 `F`（路徑 `A → C → F`）的距離為 `9m + 2m = 11m`。\n這比原本的路徑 `A → F`（`14m`）更短。\n因此，將 `F` 的距離更新為 `11m`，並調整其在佇列中的優先權。\n我們找到了更短的路徑。\n\n![Dijkstra step 9](./images/dijkstra-09.png)\n\n對於 `D` 也是如此。\n經由 `C` 的路徑 `A → C → D` 比 `A → B → D` 更短，\n因此將距離從 `22m` 更新為 `20m`。\n\n![Dijkstra step 10](./images/dijkstra-10.png)\n\n`C` 的所有鄰居已被訪問，因此將 `C` 加入 `visited` 集合。\n接著從佇列中取出下一個最近的節點 `F`。\n\n![Dijkstra step 11](./images/dijkstra-11.png)\n\n記錄到 `E` 的距離為 `11m + 9m = 20m`。\n\n![Dijkstra step 12](./images/dijkstra-12.png)\n\n將節點 `F` 加入 `visited`，接著取出下一個最近的節點 `D`。\n\n![Dijkstra step 13](./images/dijkstra-13.png)\n\n經由 `D` 到 `E` 的距離為 `20m + 6m = 26m`，\n比透過 `F` 的 `20m` 更長，因此忽略。\n\n![Dijkstra step 14](./images/dijkstra-14.png)\n\n節點 `D` 已訪問。\n\n![Dijkstra step 15](./images/dijkstra-15.png)\n\n節點 `E` 也已訪問。\n圖的遍歷完成。\n\n![Dijkstra step 16](./images/dijkstra-16.png)\n\n現在我們已經知道從起始節點 `A` 到各個節點的最短距離。\n\n在實際應用中，計算距離的同時也會記錄每個節點的 `previousVertices`（前一節點），\n以便重建出最短路徑的完整節點序列。\n\n例如，從 `A` 到 `E` 的最短路徑為：`A → C → F → E`。\n\n## 實作範例\n\n- [dijkstra.js](./dijkstra.js)\n\n## 參考資料\n\n- [維基百科](https://zh.wikipedia.org/wiki/Dijkstra算法)\n- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/__test__/dijkstra.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport dijkstra from '../dijkstra';\n\ndescribe('dijkstra', () => {\n  it('should find minimum paths to all vertices for undirected graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 4);\n    const edgeAE = new GraphEdge(vertexA, vertexE, 7);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 6);\n    const edgeBD = new GraphEdge(vertexB, vertexD, 5);\n    const edgeEC = new GraphEdge(vertexE, vertexC, 8);\n    const edgeED = new GraphEdge(vertexE, vertexD, 2);\n    const edgeDC = new GraphEdge(vertexD, vertexC, 11);\n    const edgeDG = new GraphEdge(vertexD, vertexG, 10);\n    const edgeDF = new GraphEdge(vertexD, vertexF, 2);\n    const edgeFG = new GraphEdge(vertexF, vertexG, 3);\n    const edgeEG = new GraphEdge(vertexE, vertexG, 5);\n\n    const graph = new Graph();\n    graph\n      .addVertex(vertexH)\n      .addEdge(edgeAB)\n      .addEdge(edgeAE)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeEC)\n      .addEdge(edgeED)\n      .addEdge(edgeDC)\n      .addEdge(edgeDG)\n      .addEdge(edgeDF)\n      .addEdge(edgeFG)\n      .addEdge(edgeEG);\n\n    const { distances, previousVertices } = dijkstra(graph, vertexA);\n\n    expect(distances).toEqual({\n      H: Infinity,\n      A: 0,\n      B: 4,\n      E: 7,\n      C: 3,\n      D: 9,\n      G: 12,\n      F: 11,\n    });\n\n    expect(previousVertices.F.getKey()).toBe('D');\n    expect(previousVertices.D.getKey()).toBe('B');\n    expect(previousVertices.B.getKey()).toBe('A');\n    expect(previousVertices.G.getKey()).toBe('E');\n    expect(previousVertices.C.getKey()).toBe('A');\n    expect(previousVertices.A).toBeNull();\n    expect(previousVertices.H).toBeNull();\n  });\n\n  it('should find minimum paths to all vertices for directed graph with negative edge weights', () => {\n    const vertexS = new GraphVertex('S');\n    const vertexE = new GraphVertex('E');\n    const vertexA = new GraphVertex('A');\n    const vertexD = new GraphVertex('D');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexH = new GraphVertex('H');\n\n    const edgeSE = new GraphEdge(vertexS, vertexE, 8);\n    const edgeSA = new GraphEdge(vertexS, vertexA, 10);\n    const edgeED = new GraphEdge(vertexE, vertexD, 1);\n    const edgeDA = new GraphEdge(vertexD, vertexA, -4);\n    const edgeDC = new GraphEdge(vertexD, vertexC, -1);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 2);\n    const edgeCB = new GraphEdge(vertexC, vertexB, -2);\n    const edgeBA = new GraphEdge(vertexB, vertexA, 1);\n\n    const graph = new Graph(true);\n    graph\n      .addVertex(vertexH)\n      .addEdge(edgeSE)\n      .addEdge(edgeSA)\n      .addEdge(edgeED)\n      .addEdge(edgeDA)\n      .addEdge(edgeDC)\n      .addEdge(edgeAC)\n      .addEdge(edgeCB)\n      .addEdge(edgeBA);\n\n    const { distances, previousVertices } = dijkstra(graph, vertexS);\n\n    expect(distances).toEqual({\n      H: Infinity,\n      S: 0,\n      A: 5,\n      B: 5,\n      C: 7,\n      D: 9,\n      E: 8,\n    });\n\n    expect(previousVertices.H).toBeNull();\n    expect(previousVertices.S).toBeNull();\n    expect(previousVertices.B.getKey()).toBe('C');\n    expect(previousVertices.C.getKey()).toBe('A');\n    expect(previousVertices.A.getKey()).toBe('D');\n    expect(previousVertices.D.getKey()).toBe('E');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/dijkstra/dijkstra.js",
    "content": "import PriorityQueue from '../../../data-structures/priority-queue/PriorityQueue';\n\n/**\n * @typedef {Object} ShortestPaths\n * @property {Object} distances - shortest distances to all vertices\n * @property {Object} previousVertices - shortest paths to all vertices.\n */\n\n/**\n * Implementation of Dijkstra algorithm of finding the shortest paths to graph nodes.\n * @param {Graph} graph - graph we're going to traverse.\n * @param {GraphVertex} startVertex - traversal start vertex.\n * @return {ShortestPaths}\n */\nexport default function dijkstra(graph, startVertex) {\n  // Init helper variables that we will need for Dijkstra algorithm.\n  const distances = {};\n  const visitedVertices = {};\n  const previousVertices = {};\n  const queue = new PriorityQueue();\n\n  // Init all distances with infinity assuming that currently we can't reach\n  // any of the vertices except the start one.\n  graph.getAllVertices().forEach((vertex) => {\n    distances[vertex.getKey()] = Infinity;\n    previousVertices[vertex.getKey()] = null;\n  });\n\n  // We are already at the startVertex so the distance to it is zero.\n  distances[startVertex.getKey()] = 0;\n\n  // Init vertices queue.\n  queue.add(startVertex, distances[startVertex.getKey()]);\n\n  // Iterate over the priority queue of vertices until it is empty.\n  while (!queue.isEmpty()) {\n    // Fetch next closest vertex.\n    const currentVertex = queue.poll();\n\n    // Iterate over every unvisited neighbor of the current vertex.\n    currentVertex.getNeighbors().forEach((neighbor) => {\n      // Don't visit already visited vertices.\n      if (!visitedVertices[neighbor.getKey()]) {\n        // Update distances to every neighbor from current vertex.\n        const edge = graph.findEdge(currentVertex, neighbor);\n\n        const existingDistanceToNeighbor = distances[neighbor.getKey()];\n        const distanceToNeighborFromCurrent = distances[currentVertex.getKey()] + edge.weight;\n\n        // If we've found shorter path to the neighbor - update it.\n        if (distanceToNeighborFromCurrent < existingDistanceToNeighbor) {\n          distances[neighbor.getKey()] = distanceToNeighborFromCurrent;\n\n          // Change priority of the neighbor in a queue since it might have became closer.\n          if (queue.hasValue(neighbor)) {\n            queue.changePriority(neighbor, distances[neighbor.getKey()]);\n          }\n\n          // Remember previous closest vertex.\n          previousVertices[neighbor.getKey()] = currentVertex;\n        }\n\n        // Add neighbor to the queue for further visiting.\n        if (!queue.hasValue(neighbor)) {\n          queue.add(neighbor, distances[neighbor.getKey()]);\n        }\n      }\n    });\n\n    // Add current vertex to visited ones to avoid visiting it again later.\n    visitedVertices[currentVertex.getKey()] = currentVertex;\n  }\n\n  // Return the set of shortest distances to all vertices and the set of\n  // shortest paths to all vertices in a graph.\n  return {\n    distances,\n    previousVertices,\n  };\n}\n"
  },
  {
    "path": "src/algorithms/graph/eulerian-path/README.md",
    "content": "# Eulerian Path\n\nIn graph theory, an **Eulerian trail** (or **Eulerian path**) is a \ntrail in a finite graph which visits every edge exactly once.\nSimilarly, an **Eulerian circuit** or **Eulerian cycle** is an \nEulerian trail which starts and ends on the same vertex.\n\nEuler proved that a necessary condition for the existence of Eulerian \ncircuits is that all vertices in the graph have an even degree, and \nstated that connected graphs with all vertices of even degree have \nan Eulerian circuit.\n\n![Eulerian Circuit](https://upload.wikimedia.org/wikipedia/commons/7/72/Labelled_Eulergraph.svg)\n\nEvery vertex of this graph has an even degree. Therefore, this is \nan Eulerian graph. Following the edges in alphabetical order gives \nan Eulerian circuit/cycle.\n\nFor the existence of Eulerian trails it is necessary that zero or \ntwo vertices have an odd degree; this means the Königsberg graph \nis not Eulerian. If there are no vertices of odd degree, \nall Eulerian trails are circuits. If there are exactly two vertices \nof odd degree, all Eulerian trails start at one of them and end at \nthe other. A graph that has an Eulerian trail but not an Eulerian \ncircuit is called semi-Eulerian.\n\n![Königsberg graph](https://upload.wikimedia.org/wikipedia/commons/9/96/K%C3%B6nigsberg_graph.svg)\n\nThe Königsberg Bridges multigraph. This multigraph is not Eulerian, \ntherefore, a solution does not exist.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Eulerian_path)\n- [YouTube](https://www.youtube.com/watch?v=vvP4Fg4r-Ns&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/eulerian-path/__test__/eulerianPath.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport eulerianPath from '../eulerianPath';\n\ndescribe('eulerianPath', () => {\n  it('should throw an error when graph is not Eulerian', () => {\n    function findEulerianPathInNotEulerianGraph() {\n      const vertexA = new GraphVertex('A');\n      const vertexB = new GraphVertex('B');\n      const vertexC = new GraphVertex('C');\n      const vertexD = new GraphVertex('D');\n      const vertexE = new GraphVertex('E');\n\n      const edgeAB = new GraphEdge(vertexA, vertexB);\n      const edgeAC = new GraphEdge(vertexA, vertexC);\n      const edgeBC = new GraphEdge(vertexB, vertexC);\n      const edgeBD = new GraphEdge(vertexB, vertexD);\n      const edgeCE = new GraphEdge(vertexC, vertexE);\n\n      const graph = new Graph();\n\n      graph\n        .addEdge(edgeAB)\n        .addEdge(edgeAC)\n        .addEdge(edgeBC)\n        .addEdge(edgeBD)\n        .addEdge(edgeCE);\n\n      eulerianPath(graph);\n    }\n\n    expect(findEulerianPathInNotEulerianGraph).toThrow();\n  });\n\n  it('should find Eulerian Circuit in graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeAF = new GraphEdge(vertexA, vertexF);\n    const edgeAG = new GraphEdge(vertexA, vertexG);\n    const edgeGF = new GraphEdge(vertexG, vertexF);\n    const edgeBE = new GraphEdge(vertexB, vertexE);\n    const edgeEB = new GraphEdge(vertexE, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeED = new GraphEdge(vertexE, vertexD);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAE)\n      .addEdge(edgeAF)\n      .addEdge(edgeAG)\n      .addEdge(edgeGF)\n      .addEdge(edgeBE)\n      .addEdge(edgeEB)\n      .addEdge(edgeBC)\n      .addEdge(edgeED)\n      .addEdge(edgeCD);\n\n    const graphEdgesCount = graph.getAllEdges().length;\n\n    const eulerianPathSet = eulerianPath(graph);\n\n    expect(eulerianPathSet.length).toBe(graphEdgesCount + 1);\n\n    expect(eulerianPathSet[0].getKey()).toBe(vertexA.getKey());\n    expect(eulerianPathSet[1].getKey()).toBe(vertexB.getKey());\n    expect(eulerianPathSet[2].getKey()).toBe(vertexE.getKey());\n    expect(eulerianPathSet[3].getKey()).toBe(vertexB.getKey());\n    expect(eulerianPathSet[4].getKey()).toBe(vertexC.getKey());\n    expect(eulerianPathSet[5].getKey()).toBe(vertexD.getKey());\n    expect(eulerianPathSet[6].getKey()).toBe(vertexE.getKey());\n    expect(eulerianPathSet[7].getKey()).toBe(vertexA.getKey());\n    expect(eulerianPathSet[8].getKey()).toBe(vertexF.getKey());\n    expect(eulerianPathSet[9].getKey()).toBe(vertexG.getKey());\n    expect(eulerianPathSet[10].getKey()).toBe(vertexA.getKey());\n  });\n\n  it('should find Eulerian Path in graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeBD = new GraphEdge(vertexB, vertexD);\n    const edgeDC = new GraphEdge(vertexD, vertexC);\n    const edgeCE = new GraphEdge(vertexC, vertexE);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeFH = new GraphEdge(vertexF, vertexH);\n    const edgeFG = new GraphEdge(vertexF, vertexG);\n    const edgeHG = new GraphEdge(vertexH, vertexG);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeBD)\n      .addEdge(edgeDC)\n      .addEdge(edgeCE)\n      .addEdge(edgeEF)\n      .addEdge(edgeFH)\n      .addEdge(edgeFG)\n      .addEdge(edgeHG);\n\n    const graphEdgesCount = graph.getAllEdges().length;\n\n    const eulerianPathSet = eulerianPath(graph);\n\n    expect(eulerianPathSet.length).toBe(graphEdgesCount + 1);\n\n    expect(eulerianPathSet[0].getKey()).toBe(vertexC.getKey());\n    expect(eulerianPathSet[1].getKey()).toBe(vertexA.getKey());\n    expect(eulerianPathSet[2].getKey()).toBe(vertexB.getKey());\n    expect(eulerianPathSet[3].getKey()).toBe(vertexD.getKey());\n    expect(eulerianPathSet[4].getKey()).toBe(vertexC.getKey());\n    expect(eulerianPathSet[5].getKey()).toBe(vertexE.getKey());\n    expect(eulerianPathSet[6].getKey()).toBe(vertexF.getKey());\n    expect(eulerianPathSet[7].getKey()).toBe(vertexH.getKey());\n    expect(eulerianPathSet[8].getKey()).toBe(vertexG.getKey());\n    expect(eulerianPathSet[9].getKey()).toBe(vertexF.getKey());\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/eulerian-path/eulerianPath.js",
    "content": "import graphBridges from '../bridges/graphBridges';\n\n/**\n * Fleury's algorithm of finding Eulerian Path (visit all graph edges exactly once).\n *\n * @param {Graph} graph\n * @return {GraphVertex[]}\n */\nexport default function eulerianPath(graph) {\n  const eulerianPathVertices = [];\n\n  // Set that contains all vertices with even rank (number of neighbors).\n  const evenRankVertices = {};\n\n  // Set that contains all vertices with odd rank (number of neighbors).\n  const oddRankVertices = {};\n\n  // Set of all not visited edges.\n  const notVisitedEdges = {};\n  graph.getAllEdges().forEach((vertex) => {\n    notVisitedEdges[vertex.getKey()] = vertex;\n  });\n\n  // Detect whether graph contains Eulerian Circuit or Eulerian Path or none of them.\n  /** @params {GraphVertex} vertex */\n  graph.getAllVertices().forEach((vertex) => {\n    if (vertex.getDegree() % 2) {\n      oddRankVertices[vertex.getKey()] = vertex;\n    } else {\n      evenRankVertices[vertex.getKey()] = vertex;\n    }\n  });\n\n  // Check whether we're dealing with Eulerian Circuit or Eulerian Path only.\n  // Graph would be an Eulerian Circuit in case if all its vertices has even degree.\n  // If not all vertices have even degree then graph must contain only two odd-degree\n  // vertices in order to have Euler Path.\n  const isCircuit = !Object.values(oddRankVertices).length;\n\n  if (!isCircuit && Object.values(oddRankVertices).length !== 2) {\n    throw new Error('Eulerian path must contain two odd-ranked vertices');\n  }\n\n  // Pick start vertex for traversal.\n  let startVertex = null;\n\n  if (isCircuit) {\n    // For Eulerian Circuit it doesn't matter from what vertex to start thus we'll just\n    // peek a first node.\n    const evenVertexKey = Object.keys(evenRankVertices)[0];\n    startVertex = evenRankVertices[evenVertexKey];\n  } else {\n    // For Eulerian Path we need to start from one of two odd-degree vertices.\n    const oddVertexKey = Object.keys(oddRankVertices)[0];\n    startVertex = oddRankVertices[oddVertexKey];\n  }\n\n  // Start traversing the graph.\n  let currentVertex = startVertex;\n  while (Object.values(notVisitedEdges).length) {\n    // Add current vertex to Eulerian path.\n    eulerianPathVertices.push(currentVertex);\n\n    // Detect all bridges in graph.\n    // We need to do it in order to not delete bridges if there are other edges\n    // exists for deletion.\n    const bridges = graphBridges(graph);\n\n    // Peek the next edge to delete from graph.\n    const currentEdges = currentVertex.getEdges();\n    /** @var {GraphEdge} edgeToDelete */\n    let edgeToDelete = null;\n    if (currentEdges.length === 1) {\n      // If there is only one edge left we need to peek it.\n      [edgeToDelete] = currentEdges;\n    } else {\n      // If there are many edges left then we need to peek any of those except bridges.\n      [edgeToDelete] = currentEdges.filter((edge) => !bridges[edge.getKey()]);\n    }\n\n    // Detect next current vertex.\n    if (currentVertex.getKey() === edgeToDelete.startVertex.getKey()) {\n      currentVertex = edgeToDelete.endVertex;\n    } else {\n      currentVertex = edgeToDelete.startVertex;\n    }\n\n    // Delete edge from not visited edges set.\n    delete notVisitedEdges[edgeToDelete.getKey()];\n\n    // If last edge were deleted then add finish vertex to Eulerian Path.\n    if (Object.values(notVisitedEdges).length === 0) {\n      eulerianPathVertices.push(currentVertex);\n    }\n\n    // Delete the edge from graph.\n    graph.deleteEdge(edgeToDelete);\n  }\n\n  return eulerianPathVertices;\n}\n"
  },
  {
    "path": "src/algorithms/graph/floyd-warshall/README.md",
    "content": "# Floyd–Warshall Algorithm\n\nIn computer science, the **Floyd–Warshall algorithm** is an algorithm for finding\nshortest paths in a weighted graph with positive or negative edge weights (but\nwith no negative cycles). A single execution of the algorithm will find the \nlengths (summed weights) of shortest paths between all pairs of vertices. Although \nit does not return details of the paths themselves, it is possible to reconstruct \nthe paths with simple modifications to the algorithm.\n\n## Algorithm\n\nThe Floyd–Warshall algorithm compares all possible paths through the graph between \neach pair of vertices. It is able to do this with `O(|V|^3)` comparisons in a graph.\nThis is remarkable considering that there may be up to `|V|^2` edges in the graph, \nand every combination of edges is tested. It does so by incrementally improving an \nestimate on the shortest path between two vertices, until the estimate is optimal.\n\nConsider a graph `G` with vertices `V` numbered `1` through `N`. Further consider \na function `shortestPath(i, j, k)` that returns the shortest possible path \nfrom `i` to `j` using vertices only from the set `{1, 2, ..., k}` as \nintermediate points along the way. Now, given this function, our goal is to \nfind the shortest path from each `i` to each `j` using only vertices \nin `{1, 2, ..., N}`.\n\n![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/f9b75e25063384ccca499c56f9a279abf661ad3b)\n\n![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/34ac7c89bbb18df3fd660225fd38997079e5e513)\n![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/0326d6c14def89269c029da59eba012d0f2edc9d)\n\nThis formula is the heart of the Floyd–Warshall algorithm.\n\n## Example\n\nThe algorithm above is executed on the graph on the left below:\n\n![Example](https://upload.wikimedia.org/wikipedia/commons/2/2e/Floyd-Warshall_example.svg)\n\nIn the tables below `i` is row numbers and `j` is column numbers.\n\n\n**k = 0**\n\n|       | 1   | 2   | 3   | 4   |\n|:-----:|:---:|:---:|:---:|:---:|\n| **1** |\t0   |\t∞   |\t−2  | ∞   |\n| **2** |\t4   |\t0   |\t3\t  | ∞   |\n| **3** |\t∞   |\t∞   |\t0\t  | 2   |\n| **4** |\t∞   |\t−1  | ∞   | 0   |\n\n\n**k = 1**\n\n|       | 1   | 2   | 3   | 4   |\n|:-----:|:---:|:---:|:---:|:---:|\n| **1** | 0   | ∞   | −2  | ∞   |\n| **2** | 4   | 0   |  2  | ∞   |\n| **3** | ∞   | ∞   |  0  | 2   |\n| **4** | ∞   | −   |  ∞  | 0   |\n\n\n**k = 2**\n\n|       | 1   | 2   | 3   | 4   |\n|:-----:|:---:|:---:|:---:|:---:|\n| **1** |\t0   |\t∞   |\t−2  | ∞   |\n| **2** |\t4   |\t0   | 2\t  | ∞   |\n| **3** |\t∞   |\t∞\t  | 0\t  | 2   |\n| **4** |\t3   |\t−1  | 1   | 0   |\n\n\n**k = 3**\n\n|       | 1   | 2   | 3   | 4   |\n|:-----:|:---:|:---:|:---:|:---:|\n| **1** |\t0   |\t∞   |\t−2  | 0   |\n| **2** |\t4   |\t0   |\t2\t  | 4   |\n| **3** |\t∞   |\t∞   |\t0\t  | 2   |\n| **4** |\t3   |\t−1  | 1   | 0   |\n\n\n**k = 4**\n\n|       | 1   | 2   | 3   | 4   |\n|:-----:|:---:|:---:|:---:|:---:|\n| **1** |\t0   |\t−1  | −2  | 0   |\n| **2** |\t4   |\t0\t  | 2\t  | 4   |\n| **3** |\t5   |\t1\t  | 0\t  | 2   |\n| **4** |\t3   |\t−1  | 1   | 0   |\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)\n- [YouTube (by Abdul Bari)](https://www.youtube.com/watch?v=oNI0rf2P9gE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=74)\n- [YouTube (by Tushar Roy)](https://www.youtube.com/watch?v=LwJdNfdLF9s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=75)\n"
  },
  {
    "path": "src/algorithms/graph/floyd-warshall/__test__/floydWarshall.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport floydWarshall from '../floydWarshall';\n\ndescribe('floydWarshall', () => {\n  it('should find minimum paths to all vertices for undirected graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 4);\n    const edgeAE = new GraphEdge(vertexA, vertexE, 7);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 6);\n    const edgeBD = new GraphEdge(vertexB, vertexD, 5);\n    const edgeEC = new GraphEdge(vertexE, vertexC, 8);\n    const edgeED = new GraphEdge(vertexE, vertexD, 2);\n    const edgeDC = new GraphEdge(vertexD, vertexC, 11);\n    const edgeDG = new GraphEdge(vertexD, vertexG, 10);\n    const edgeDF = new GraphEdge(vertexD, vertexF, 2);\n    const edgeFG = new GraphEdge(vertexF, vertexG, 3);\n    const edgeEG = new GraphEdge(vertexE, vertexG, 5);\n\n    const graph = new Graph();\n\n    // Add vertices first just to have them in desired order.\n    graph\n      .addVertex(vertexA)\n      .addVertex(vertexB)\n      .addVertex(vertexC)\n      .addVertex(vertexD)\n      .addVertex(vertexE)\n      .addVertex(vertexF)\n      .addVertex(vertexG)\n      .addVertex(vertexH);\n\n    // Now, when vertices are in correct order let's add edges.\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAE)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeEC)\n      .addEdge(edgeED)\n      .addEdge(edgeDC)\n      .addEdge(edgeDG)\n      .addEdge(edgeDF)\n      .addEdge(edgeFG)\n      .addEdge(edgeEG);\n\n    const { distances, nextVertices } = floydWarshall(graph);\n\n    const vertices = graph.getAllVertices();\n\n    const vertexAIndex = vertices.indexOf(vertexA);\n    const vertexBIndex = vertices.indexOf(vertexB);\n    const vertexCIndex = vertices.indexOf(vertexC);\n    const vertexDIndex = vertices.indexOf(vertexD);\n    const vertexEIndex = vertices.indexOf(vertexE);\n    const vertexFIndex = vertices.indexOf(vertexF);\n    const vertexGIndex = vertices.indexOf(vertexG);\n    const vertexHIndex = vertices.indexOf(vertexH);\n\n    expect(distances[vertexAIndex][vertexHIndex]).toBe(Infinity);\n    expect(distances[vertexAIndex][vertexAIndex]).toBe(0);\n    expect(distances[vertexAIndex][vertexBIndex]).toBe(4);\n    expect(distances[vertexAIndex][vertexEIndex]).toBe(7);\n    expect(distances[vertexAIndex][vertexCIndex]).toBe(3);\n    expect(distances[vertexAIndex][vertexDIndex]).toBe(9);\n    expect(distances[vertexAIndex][vertexGIndex]).toBe(12);\n    expect(distances[vertexAIndex][vertexFIndex]).toBe(11);\n\n    expect(nextVertices[vertexAIndex][vertexFIndex]).toBe(vertexD);\n    expect(nextVertices[vertexAIndex][vertexDIndex]).toBe(vertexB);\n    expect(nextVertices[vertexAIndex][vertexBIndex]).toBe(vertexA);\n    expect(nextVertices[vertexAIndex][vertexGIndex]).toBe(vertexE);\n    expect(nextVertices[vertexAIndex][vertexCIndex]).toBe(vertexA);\n    expect(nextVertices[vertexAIndex][vertexAIndex]).toBe(null);\n    expect(nextVertices[vertexAIndex][vertexHIndex]).toBe(null);\n  });\n\n  it('should find minimum paths to all vertices for directed graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 3);\n    const edgeBA = new GraphEdge(vertexB, vertexA, 8);\n    const edgeAD = new GraphEdge(vertexA, vertexD, 7);\n    const edgeDA = new GraphEdge(vertexD, vertexA, 2);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 2);\n    const edgeCA = new GraphEdge(vertexC, vertexA, 5);\n    const edgeCD = new GraphEdge(vertexC, vertexD, 1);\n\n    const graph = new Graph(true);\n\n    // Add vertices first just to have them in desired order.\n    graph\n      .addVertex(vertexA)\n      .addVertex(vertexB)\n      .addVertex(vertexC)\n      .addVertex(vertexD);\n\n    // Now, when vertices are in correct order let's add edges.\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBA)\n      .addEdge(edgeAD)\n      .addEdge(edgeDA)\n      .addEdge(edgeBC)\n      .addEdge(edgeCA)\n      .addEdge(edgeCD);\n\n    const { distances, nextVertices } = floydWarshall(graph);\n\n    const vertices = graph.getAllVertices();\n\n    const vertexAIndex = vertices.indexOf(vertexA);\n    const vertexBIndex = vertices.indexOf(vertexB);\n    const vertexCIndex = vertices.indexOf(vertexC);\n    const vertexDIndex = vertices.indexOf(vertexD);\n\n    expect(distances[vertexAIndex][vertexAIndex]).toBe(0);\n    expect(distances[vertexAIndex][vertexBIndex]).toBe(3);\n    expect(distances[vertexAIndex][vertexCIndex]).toBe(5);\n    expect(distances[vertexAIndex][vertexDIndex]).toBe(6);\n\n    expect(distances).toEqual([\n      [0, 3, 5, 6],\n      [5, 0, 2, 3],\n      [3, 6, 0, 1],\n      [2, 5, 7, 0],\n    ]);\n\n    expect(nextVertices[vertexAIndex][vertexDIndex]).toBe(vertexC);\n    expect(nextVertices[vertexAIndex][vertexCIndex]).toBe(vertexB);\n    expect(nextVertices[vertexBIndex][vertexDIndex]).toBe(vertexC);\n    expect(nextVertices[vertexAIndex][vertexAIndex]).toBe(null);\n    expect(nextVertices[vertexAIndex][vertexBIndex]).toBe(vertexA);\n  });\n\n  it('should find minimum paths to all vertices for directed graph with negative edge weights', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeFE = new GraphEdge(vertexF, vertexE, 8);\n    const edgeFA = new GraphEdge(vertexF, vertexA, 10);\n    const edgeED = new GraphEdge(vertexE, vertexD, 1);\n    const edgeDA = new GraphEdge(vertexD, vertexA, -4);\n    const edgeDC = new GraphEdge(vertexD, vertexC, -1);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 2);\n    const edgeCB = new GraphEdge(vertexC, vertexB, -2);\n    const edgeBA = new GraphEdge(vertexB, vertexA, 1);\n\n    const graph = new Graph(true);\n\n    // Add vertices first just to have them in desired order.\n    graph\n      .addVertex(vertexA)\n      .addVertex(vertexB)\n      .addVertex(vertexC)\n      .addVertex(vertexD)\n      .addVertex(vertexE)\n      .addVertex(vertexF)\n      .addVertex(vertexG);\n\n    // Now, when vertices are in correct order let's add edges.\n    graph\n      .addEdge(edgeFE)\n      .addEdge(edgeFA)\n      .addEdge(edgeED)\n      .addEdge(edgeDA)\n      .addEdge(edgeDC)\n      .addEdge(edgeAC)\n      .addEdge(edgeCB)\n      .addEdge(edgeBA);\n\n    const { distances, nextVertices } = floydWarshall(graph);\n\n    const vertices = graph.getAllVertices();\n\n    const vertexAIndex = vertices.indexOf(vertexA);\n    const vertexBIndex = vertices.indexOf(vertexB);\n    const vertexCIndex = vertices.indexOf(vertexC);\n    const vertexDIndex = vertices.indexOf(vertexD);\n    const vertexEIndex = vertices.indexOf(vertexE);\n    const vertexGIndex = vertices.indexOf(vertexG);\n    const vertexFIndex = vertices.indexOf(vertexF);\n\n    expect(distances[vertexFIndex][vertexGIndex]).toBe(Infinity);\n    expect(distances[vertexFIndex][vertexFIndex]).toBe(0);\n    expect(distances[vertexFIndex][vertexAIndex]).toBe(5);\n    expect(distances[vertexFIndex][vertexBIndex]).toBe(5);\n    expect(distances[vertexFIndex][vertexCIndex]).toBe(7);\n    expect(distances[vertexFIndex][vertexDIndex]).toBe(9);\n    expect(distances[vertexFIndex][vertexEIndex]).toBe(8);\n\n    expect(nextVertices[vertexFIndex][vertexGIndex]).toBe(null);\n    expect(nextVertices[vertexFIndex][vertexFIndex]).toBe(null);\n    expect(nextVertices[vertexAIndex][vertexBIndex]).toBe(vertexC);\n    expect(nextVertices[vertexAIndex][vertexCIndex]).toBe(vertexA);\n    expect(nextVertices[vertexFIndex][vertexBIndex]).toBe(vertexE);\n    expect(nextVertices[vertexEIndex][vertexBIndex]).toBe(vertexD);\n    expect(nextVertices[vertexDIndex][vertexBIndex]).toBe(vertexC);\n    expect(nextVertices[vertexCIndex][vertexBIndex]).toBe(vertexC);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/floyd-warshall/floydWarshall.js",
    "content": "/**\n * @param {Graph} graph\n * @return {{distances: number[][], nextVertices: GraphVertex[][]}}\n */\nexport default function floydWarshall(graph) {\n  // Get all graph vertices.\n  const vertices = graph.getAllVertices();\n\n  // Init previous vertices matrix with nulls meaning that there are no\n  // previous vertices exist that will give us shortest path.\n  const nextVertices = Array(vertices.length).fill(null).map(() => {\n    return Array(vertices.length).fill(null);\n  });\n\n  // Init distances matrix with Infinities meaning there are no paths\n  // between vertices exist so far.\n  const distances = Array(vertices.length).fill(null).map(() => {\n    return Array(vertices.length).fill(Infinity);\n  });\n\n  // Init distance matrix with the distance we already now (from existing edges).\n  // And also init previous vertices from the edges.\n  vertices.forEach((startVertex, startIndex) => {\n    vertices.forEach((endVertex, endIndex) => {\n      if (startVertex === endVertex) {\n        // Distance to the vertex itself is 0.\n        distances[startIndex][endIndex] = 0;\n      } else {\n        // Find edge between the start and end vertices.\n        const edge = graph.findEdge(startVertex, endVertex);\n\n        if (edge) {\n          // There is an edge from vertex with startIndex to vertex with endIndex.\n          // Save distance and previous vertex.\n          distances[startIndex][endIndex] = edge.weight;\n          nextVertices[startIndex][endIndex] = startVertex;\n        } else {\n          distances[startIndex][endIndex] = Infinity;\n        }\n      }\n    });\n  });\n\n  // Now let's go to the core of the algorithm.\n  // Let's all pair of vertices (from start to end ones) and try to check if there\n  // is a shorter path exists between them via middle vertex. Middle vertex may also\n  // be one of the graph vertices. As you may see now we're going to have three\n  // loops over all graph vertices: for start, end and middle vertices.\n  vertices.forEach((middleVertex, middleIndex) => {\n    // Path starts from startVertex with startIndex.\n    vertices.forEach((startVertex, startIndex) => {\n      // Path ends to endVertex with endIndex.\n      vertices.forEach((endVertex, endIndex) => {\n        // Compare existing distance from startVertex to endVertex, with distance\n        // from startVertex to endVertex but via middleVertex.\n        // Save the shortest distance and previous vertex that allows\n        // us to have this shortest distance.\n        const distViaMiddle = distances[startIndex][middleIndex] + distances[middleIndex][endIndex];\n\n        if (distances[startIndex][endIndex] > distViaMiddle) {\n          // We've found a shortest pass via middle vertex.\n          distances[startIndex][endIndex] = distViaMiddle;\n          nextVertices[startIndex][endIndex] = middleVertex;\n        }\n      });\n    });\n  });\n\n  // Shortest distance from x to y: distance[x][y].\n  // Next vertex after x one in path from x to y: nextVertices[x][y].\n  return { distances, nextVertices };\n}\n"
  },
  {
    "path": "src/algorithms/graph/hamiltonian-cycle/README.md",
    "content": "# Hamiltonian Path\n\n**Hamiltonian path** (or **traceable path**) is a path in an \nundirected or directed graph that visits each vertex exactly once. \nA **Hamiltonian cycle** (or **Hamiltonian circuit**) is a \nHamiltonian path that is a cycle. Determining whether such paths \nand cycles exist in graphs is the **Hamiltonian path problem**.\n\n![Hamiltonian cycle](https://upload.wikimedia.org/wikipedia/commons/6/6c/Hamiltonian_path_3d.svg)\n\nOne possible Hamiltonian cycle through every vertex of a \ndodecahedron is shown in red – like all platonic solids, the \ndodecahedron is Hamiltonian.\n\n## Naive Algorithm\n\nGenerate all possible configurations of vertices and print a \nconfiguration that satisfies the given constraints. There \nwill be `n!` (n factorial) configurations.\n\n```\nwhile there are untried configurations\n{\n   generate the next configuration\n   if ( there are edges between two consecutive vertices of this\n      configuration and there is an edge from the last vertex to \n      the first ).\n   {\n      print this configuration;\n      break;\n   }\n}\n```\n\n## Backtracking Algorithm\n\nCreate an empty path array and add vertex `0` to it. Add other \nvertices, starting from the vertex `1`. Before adding a vertex, \ncheck for whether it is adjacent to the previously added vertex \nand not already added. If we find such a vertex, we add the \nvertex as part of the solution. If we do not find a vertex \nthen we return false.\n\n## References\n\n- [Hamiltonian path on Wikipedia](https://en.wikipedia.org/wiki/Hamiltonian_path)\n- [Hamiltonian path on YouTube](https://www.youtube.com/watch?v=dQr4wZCiJJ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Hamiltonian cycle on GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-7-hamiltonian-cycle/)\n"
  },
  {
    "path": "src/algorithms/graph/hamiltonian-cycle/__test__/hamiltonianCycle.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport hamiltonianCycle from '../hamiltonianCycle';\n\ndescribe('hamiltonianCycle', () => {\n  it('should find hamiltonian paths in graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeBE = new GraphEdge(vertexB, vertexE);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeBD = new GraphEdge(vertexB, vertexD);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n\n    const graph = new Graph();\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAE)\n      .addEdge(edgeAC)\n      .addEdge(edgeBE)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeCD)\n      .addEdge(edgeDE);\n\n    const hamiltonianCycleSet = hamiltonianCycle(graph);\n\n    expect(hamiltonianCycleSet.length).toBe(8);\n\n    expect(hamiltonianCycleSet[0][0].getKey()).toBe(vertexA.getKey());\n    expect(hamiltonianCycleSet[0][1].getKey()).toBe(vertexB.getKey());\n    expect(hamiltonianCycleSet[0][2].getKey()).toBe(vertexE.getKey());\n    expect(hamiltonianCycleSet[0][3].getKey()).toBe(vertexD.getKey());\n    expect(hamiltonianCycleSet[0][4].getKey()).toBe(vertexC.getKey());\n\n    expect(hamiltonianCycleSet[1][0].getKey()).toBe(vertexA.getKey());\n    expect(hamiltonianCycleSet[1][1].getKey()).toBe(vertexB.getKey());\n    expect(hamiltonianCycleSet[1][2].getKey()).toBe(vertexC.getKey());\n    expect(hamiltonianCycleSet[1][3].getKey()).toBe(vertexD.getKey());\n    expect(hamiltonianCycleSet[1][4].getKey()).toBe(vertexE.getKey());\n\n    expect(hamiltonianCycleSet[2][0].getKey()).toBe(vertexA.getKey());\n    expect(hamiltonianCycleSet[2][1].getKey()).toBe(vertexE.getKey());\n    expect(hamiltonianCycleSet[2][2].getKey()).toBe(vertexB.getKey());\n    expect(hamiltonianCycleSet[2][3].getKey()).toBe(vertexD.getKey());\n    expect(hamiltonianCycleSet[2][4].getKey()).toBe(vertexC.getKey());\n\n    expect(hamiltonianCycleSet[3][0].getKey()).toBe(vertexA.getKey());\n    expect(hamiltonianCycleSet[3][1].getKey()).toBe(vertexE.getKey());\n    expect(hamiltonianCycleSet[3][2].getKey()).toBe(vertexD.getKey());\n    expect(hamiltonianCycleSet[3][3].getKey()).toBe(vertexB.getKey());\n    expect(hamiltonianCycleSet[3][4].getKey()).toBe(vertexC.getKey());\n  });\n\n  it('should return false for graph without Hamiltonian path', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAE = new GraphEdge(vertexA, vertexE);\n    const edgeBE = new GraphEdge(vertexB, vertexE);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeBD = new GraphEdge(vertexB, vertexD);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n\n    const graph = new Graph();\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAE)\n      .addEdge(edgeBE)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeCD);\n\n    const hamiltonianCycleSet = hamiltonianCycle(graph);\n\n    expect(hamiltonianCycleSet.length).toBe(0);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/hamiltonian-cycle/hamiltonianCycle.js",
    "content": "import GraphVertex from '../../../data-structures/graph/GraphVertex';\n\n/**\n * @param {number[][]} adjacencyMatrix\n * @param {object} verticesIndices\n * @param {GraphVertex[]} cycle\n * @param {GraphVertex} vertexCandidate\n * @return {boolean}\n */\nfunction isSafe(adjacencyMatrix, verticesIndices, cycle, vertexCandidate) {\n  const endVertex = cycle[cycle.length - 1];\n\n  // Get end and candidate vertices indices in adjacency matrix.\n  const candidateVertexAdjacencyIndex = verticesIndices[vertexCandidate.getKey()];\n  const endVertexAdjacencyIndex = verticesIndices[endVertex.getKey()];\n\n  // Check if last vertex in the path and candidate vertex are adjacent.\n  if (adjacencyMatrix[endVertexAdjacencyIndex][candidateVertexAdjacencyIndex] === Infinity) {\n    return false;\n  }\n\n  // Check if vertexCandidate is being added to the path for the first time.\n  const candidateDuplicate = cycle.find((vertex) => vertex.getKey() === vertexCandidate.getKey());\n\n  return !candidateDuplicate;\n}\n\n/**\n * @param {number[][]} adjacencyMatrix\n * @param {object} verticesIndices\n * @param {GraphVertex[]} cycle\n * @return {boolean}\n */\nfunction isCycle(adjacencyMatrix, verticesIndices, cycle) {\n  // Check if first and last vertices in hamiltonian path are adjacent.\n\n  // Get start and end vertices from the path.\n  const startVertex = cycle[0];\n  const endVertex = cycle[cycle.length - 1];\n\n  // Get start/end vertices indices in adjacency matrix.\n  const startVertexAdjacencyIndex = verticesIndices[startVertex.getKey()];\n  const endVertexAdjacencyIndex = verticesIndices[endVertex.getKey()];\n\n  // Check if we can go from end vertex to the start one.\n  return adjacencyMatrix[endVertexAdjacencyIndex][startVertexAdjacencyIndex] !== Infinity;\n}\n\n/**\n * @param {number[][]} adjacencyMatrix\n * @param {GraphVertex[]} vertices\n * @param {object} verticesIndices\n * @param {GraphVertex[][]} cycles\n * @param {GraphVertex[]} cycle\n */\nfunction hamiltonianCycleRecursive({\n  adjacencyMatrix,\n  vertices,\n  verticesIndices,\n  cycles,\n  cycle,\n}) {\n  // Clone cycle in order to prevent it from modification by other DFS branches.\n  const currentCycle = [...cycle].map((vertex) => new GraphVertex(vertex.value));\n\n  if (vertices.length === currentCycle.length) {\n    // Hamiltonian path is found.\n    // Now we need to check if it is cycle or not.\n    if (isCycle(adjacencyMatrix, verticesIndices, currentCycle)) {\n      // Another solution has been found. Save it.\n      cycles.push(currentCycle);\n    }\n    return;\n  }\n\n  for (let vertexIndex = 0; vertexIndex < vertices.length; vertexIndex += 1) {\n    // Get vertex candidate that we will try to put into next path step and see if it fits.\n    const vertexCandidate = vertices[vertexIndex];\n\n    // Check if it is safe to put vertex candidate to cycle.\n    if (isSafe(adjacencyMatrix, verticesIndices, currentCycle, vertexCandidate)) {\n      // Add candidate vertex to cycle path.\n      currentCycle.push(vertexCandidate);\n\n      // Try to find other vertices in cycle.\n      hamiltonianCycleRecursive({\n        adjacencyMatrix,\n        vertices,\n        verticesIndices,\n        cycles,\n        cycle: currentCycle,\n      });\n\n      // BACKTRACKING.\n      // Remove candidate vertex from cycle path in order to try another one.\n      currentCycle.pop();\n    }\n  }\n}\n\n/**\n * @param {Graph} graph\n * @return {GraphVertex[][]}\n */\nexport default function hamiltonianCycle(graph) {\n  // Gather some information about the graph that we will need to during\n  // the problem solving.\n  const verticesIndices = graph.getVerticesIndices();\n  const adjacencyMatrix = graph.getAdjacencyMatrix();\n  const vertices = graph.getAllVertices();\n\n  // Define start vertex. We will always pick the first one\n  // this it doesn't matter which vertex to pick in a cycle.\n  // Every vertex is in a cycle so we can start from any of them.\n  const startVertex = vertices[0];\n\n  // Init cycles array that will hold all solutions.\n  const cycles = [];\n\n  // Init cycle array that will hold current cycle path.\n  const cycle = [startVertex];\n\n  // Try to find cycles recursively in Depth First Search order.\n  hamiltonianCycleRecursive({\n    adjacencyMatrix,\n    vertices,\n    verticesIndices,\n    cycles,\n    cycle,\n  });\n\n  // Return found cycles.\n  return cycles;\n}\n"
  },
  {
    "path": "src/algorithms/graph/kruskal/README.ko-KR.md",
    "content": "# 크루스칼 알고리즘\n\n크루스칼 알고리즘은 두 트리를 연결하는 최소 간선 가중치를 찾는 최소 신장 트리 알고리즘입니다.\n각 단계에서 비용을 더하는 연결된 가중 그래프에 대한 최소 신장 트리를 찾기 때문에 그래프 이론에서의 그리디 알고리즘입니다. 즉, 트리의 모든 간선의 총 가중치가 최소화되는 모든 정점을 포함하는 트리를 형성하는 간선의 하위 집합을 찾습니다. 그래프가 연결되어 있지 않으면 최소 신장 포레스트(연결된 각 구성 요소의 최소 신장 트리)를 찾습니다.\n\n![Kruskal Algorithm](https://upload.wikimedia.org/wikipedia/commons/5/5c/MST_kruskal_en.gif)\n\n![Kruskal Demo](https://upload.wikimedia.org/wikipedia/commons/b/bb/KruskalDemo.gif)\n\n유클리드 거리를 기반으로 한 크루스칼 알고리즘의 데모입니다.\n\n## 최소 신장 트리\n\n**최소 신장 트리(MST)** 또는 최소 가중치 신장 트리는 연결된 간선 가중치 무 방향 그래프의 간선의 하위 집합으로, 사이클 없이 가능한 최소 총 간선 가중치로 모든 정점을 연결합니다. 즉, 간선 가중치의 합이 가능한 작은 신장 트리입니다. 보다 일반적으로, 간선-가중치 비방향 그래프(꼭 연결되지는 않음)에는 연결된 구성 요소에 대한 최소 신장 트리의 결합인 최소 신장 포레스트(minimum spanning forest)가 있습니다.\n\n![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)\n\n평면 그래프와 해당 최소 신장 트리입니다. 각 간선은 가중치로 레이블이 지정되며, 이 값은 길이에 거의 비례합니다.\n\n![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)\n\n이 그림은 그래프에 최소 신장 트리가 두 개 이상 있을 수 있음을 보여 줍니다. 그림에서 그래프 아래의 두 트리는 주어진 그래프에서 최소 신장 트리가 될 수 있는 두 가지 경우입니다.\n\n## 참조\n\n- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)\n- [Kruskal's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Kruskal%27s_algorithm)\n- [Kruskal's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=fAuF0EuZVCk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Kruskal's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=71UQH7Pr9kU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/kruskal/README.md",
    "content": "# Kruskal's Algorithm\n\n_Read this in other languages:_\n[_한국어_](README.ko-KR.md)\n\nKruskal's algorithm is a minimum-spanning-tree algorithm which \nfinds an edge of the least possible weight that connects any two \ntrees in the forest. It is a greedy algorithm in graph theory \nas it finds a minimum spanning tree for a connected weighted \ngraph adding increasing cost arcs at each step. This means it \nfinds a subset of the edges that forms a tree that includes every\nvertex, where the total weight of all the edges in the tree is \nminimized. If the graph is not connected, then it finds a \nminimum spanning forest (a minimum spanning tree for each \nconnected component).\n\n![Kruskal Algorithm](https://upload.wikimedia.org/wikipedia/commons/5/5c/MST_kruskal_en.gif)\n\n![Kruskal Demo](https://upload.wikimedia.org/wikipedia/commons/b/bb/KruskalDemo.gif)\n\nA demo for Kruskal's algorithm based on Euclidean distance.\n\n## Minimum Spanning Tree\n\nA **minimum spanning tree** (MST) or minimum weight spanning tree \nis a subset of the edges of a connected, edge-weighted \n(un)directed graph that connects all the vertices together, \nwithout any cycles and with the minimum possible total edge \nweight. That is, it is a spanning tree whose sum of edge weights \nis as small as possible. More generally, any edge-weighted \nundirected graph (not necessarily connected) has a minimum \nspanning forest, which is a union of the minimum spanning \ntrees for its connected components.\n\n![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)\n\nA planar graph and its minimum spanning tree. Each edge is \nlabeled with its weight, which here is roughly proportional \nto its length.\n\n![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)\n\nThis figure shows there may be more than one minimum spanning \ntree in a graph. In the figure, the two trees below the graph \nare two possibilities of minimum spanning tree of the given graph.\n\n## References\n\n- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)\n- [Kruskal's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Kruskal%27s_algorithm)\n- [Kruskal's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=fAuF0EuZVCk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Kruskal's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=71UQH7Pr9kU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/kruskal/__test__/kruskal.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport kruskal from '../kruskal';\n\ndescribe('kruskal', () => {\n  it('should fire an error for directed graph', () => {\n    function applyPrimToDirectedGraph() {\n      const graph = new Graph(true);\n\n      kruskal(graph);\n    }\n\n    expect(applyPrimToDirectedGraph).toThrow();\n  });\n\n  it('should find minimum spanning tree', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 2);\n    const edgeAD = new GraphEdge(vertexA, vertexD, 3);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 4);\n    const edgeBE = new GraphEdge(vertexB, vertexE, 3);\n    const edgeDF = new GraphEdge(vertexD, vertexF, 7);\n    const edgeEC = new GraphEdge(vertexE, vertexC, 1);\n    const edgeEF = new GraphEdge(vertexE, vertexF, 8);\n    const edgeFG = new GraphEdge(vertexF, vertexG, 9);\n    const edgeFC = new GraphEdge(vertexF, vertexC, 6);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAD)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeBE)\n      .addEdge(edgeDF)\n      .addEdge(edgeEC)\n      .addEdge(edgeEF)\n      .addEdge(edgeFC)\n      .addEdge(edgeFG);\n\n    expect(graph.getWeight()).toEqual(46);\n\n    const minimumSpanningTree = kruskal(graph);\n\n    expect(minimumSpanningTree.getWeight()).toBe(24);\n    expect(minimumSpanningTree.getAllVertices().length).toBe(graph.getAllVertices().length);\n    expect(minimumSpanningTree.getAllEdges().length).toBe(graph.getAllVertices().length - 1);\n    expect(minimumSpanningTree.toString()).toBe('E,C,A,B,D,F,G');\n  });\n\n  it('should find minimum spanning tree for simple graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 1);\n    const edgeAD = new GraphEdge(vertexA, vertexD, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 1);\n    const edgeBD = new GraphEdge(vertexB, vertexD, 3);\n    const edgeCD = new GraphEdge(vertexC, vertexD, 1);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAD)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeCD);\n\n    expect(graph.getWeight()).toEqual(9);\n\n    const minimumSpanningTree = kruskal(graph);\n\n    expect(minimumSpanningTree.getWeight()).toBe(3);\n    expect(minimumSpanningTree.getAllVertices().length).toBe(graph.getAllVertices().length);\n    expect(minimumSpanningTree.getAllEdges().length).toBe(graph.getAllVertices().length - 1);\n    expect(minimumSpanningTree.toString()).toBe('A,B,C,D');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/kruskal/kruskal.js",
    "content": "import Graph from '../../../data-structures/graph/Graph';\nimport QuickSort from '../../sorting/quick-sort/QuickSort';\nimport DisjointSet from '../../../data-structures/disjoint-set/DisjointSet';\n\n/**\n * @param {Graph} graph\n * @return {Graph}\n */\nexport default function kruskal(graph) {\n  // It should fire error if graph is directed since the algorithm works only\n  // for undirected graphs.\n  if (graph.isDirected) {\n    throw new Error('Kruskal\\'s algorithms works only for undirected graphs');\n  }\n\n  // Init new graph that will contain minimum spanning tree of original graph.\n  const minimumSpanningTree = new Graph();\n\n  // Sort all graph edges in increasing order.\n  const sortingCallbacks = {\n    /**\n     * @param {GraphEdge} graphEdgeA\n     * @param {GraphEdge} graphEdgeB\n     */\n    compareCallback: (graphEdgeA, graphEdgeB) => {\n      if (graphEdgeA.weight === graphEdgeB.weight) {\n        return 1;\n      }\n\n      return graphEdgeA.weight <= graphEdgeB.weight ? -1 : 1;\n    },\n  };\n  const sortedEdges = new QuickSort(sortingCallbacks).sort(graph.getAllEdges());\n\n  // Create disjoint sets for all graph vertices.\n  const keyCallback = (graphVertex) => graphVertex.getKey();\n  const disjointSet = new DisjointSet(keyCallback);\n\n  graph.getAllVertices().forEach((graphVertex) => {\n    disjointSet.makeSet(graphVertex);\n  });\n\n  // Go through all edges started from the minimum one and try to add them\n  // to minimum spanning tree. The criteria of adding the edge would be whether\n  // it is forms the cycle or not (if it connects two vertices from one disjoint\n  // set or not).\n  for (let edgeIndex = 0; edgeIndex < sortedEdges.length; edgeIndex += 1) {\n    /** @var {GraphEdge} currentEdge */\n    const currentEdge = sortedEdges[edgeIndex];\n\n    // Check if edge forms the cycle. If it does then skip it.\n    if (!disjointSet.inSameSet(currentEdge.startVertex, currentEdge.endVertex)) {\n      // Unite two subsets into one.\n      disjointSet.union(currentEdge.startVertex, currentEdge.endVertex);\n\n      // Add this edge to spanning tree.\n      minimumSpanningTree.addEdge(currentEdge);\n    }\n  }\n\n  return minimumSpanningTree;\n}\n"
  },
  {
    "path": "src/algorithms/graph/prim/README.md",
    "content": "# Prim's Algorithm\n\nIn computer science, **Prim's algorithm** is a greedy algorithm that \nfinds a minimum spanning tree for a weighted undirected graph. \n\nThe algorithm operates by building this tree one vertex at a \ntime, from an arbitrary starting vertex, at each step adding \nthe cheapest possible connection from the tree to another vertex.\n\n![Prim's Algorithm](https://upload.wikimedia.org/wikipedia/commons/f/f7/Prim%27s_algorithm.svg)\n\nPrim's algorithm starting at vertex `A`. In the third step, edges \n`BD` and `AB` both have weight `2`, so `BD` is chosen arbitrarily. \nAfter that step, `AB` is no longer a candidate for addition \nto the tree because it links two nodes that are already \nin the tree.\n\n## Minimum Spanning Tree\n\nA **minimum spanning tree** (MST) or minimum weight spanning tree \nis a subset of the edges of a connected, edge-weighted \n(un)directed graph that connects all the vertices together, \nwithout any cycles and with the minimum possible total edge \nweight. That is, it is a spanning tree whose sum of edge weights \nis as small as possible. More generally, any edge-weighted \nundirected graph (not necessarily connected) has a minimum \nspanning forest, which is a union of the minimum spanning \ntrees for its connected components.\n\n![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)\n\nA planar graph and its minimum spanning tree. Each edge is \nlabeled with its weight, which here is roughly proportional \nto its length.\n\n![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)\n\nThis figure shows there may be more than one minimum spanning \ntree in a graph. In the figure, the two trees below the graph \nare two possibilities of minimum spanning tree of the given graph.\n\n## References\n\n- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)\n- [Prim's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Prim%27s_algorithm)\n- [Prim's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=oP2-8ysT3QQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Prim's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=cplfcGZmX7I&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/prim/__test__/prim.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport prim from '../prim';\n\ndescribe('prim', () => {\n  it('should fire an error for directed graph', () => {\n    function applyPrimToDirectedGraph() {\n      const graph = new Graph(true);\n\n      prim(graph);\n    }\n\n    expect(applyPrimToDirectedGraph).toThrow();\n  });\n\n  it('should find minimum spanning tree', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 2);\n    const edgeAD = new GraphEdge(vertexA, vertexD, 3);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 4);\n    const edgeBE = new GraphEdge(vertexB, vertexE, 3);\n    const edgeDF = new GraphEdge(vertexD, vertexF, 7);\n    const edgeEC = new GraphEdge(vertexE, vertexC, 1);\n    const edgeEF = new GraphEdge(vertexE, vertexF, 8);\n    const edgeFG = new GraphEdge(vertexF, vertexG, 9);\n    const edgeFC = new GraphEdge(vertexF, vertexC, 6);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAD)\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeBE)\n      .addEdge(edgeDF)\n      .addEdge(edgeEC)\n      .addEdge(edgeEF)\n      .addEdge(edgeFC)\n      .addEdge(edgeFG);\n\n    expect(graph.getWeight()).toEqual(46);\n\n    const minimumSpanningTree = prim(graph);\n\n    expect(minimumSpanningTree.getWeight()).toBe(24);\n    expect(minimumSpanningTree.getAllVertices().length).toBe(graph.getAllVertices().length);\n    expect(minimumSpanningTree.getAllEdges().length).toBe(graph.getAllVertices().length - 1);\n    expect(minimumSpanningTree.toString()).toBe('A,B,C,E,D,F,G');\n  });\n\n  it('should find minimum spanning tree for simple graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 1);\n    const edgeAD = new GraphEdge(vertexA, vertexD, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 1);\n    const edgeBD = new GraphEdge(vertexB, vertexD, 3);\n    const edgeCD = new GraphEdge(vertexC, vertexD, 1);\n\n    const graph = new Graph();\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAD)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeCD);\n\n    expect(graph.getWeight()).toEqual(9);\n\n    const minimumSpanningTree = prim(graph);\n\n    expect(minimumSpanningTree.getWeight()).toBe(3);\n    expect(minimumSpanningTree.getAllVertices().length).toBe(graph.getAllVertices().length);\n    expect(minimumSpanningTree.getAllEdges().length).toBe(graph.getAllVertices().length - 1);\n    expect(minimumSpanningTree.toString()).toBe('A,B,C,D');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/prim/prim.js",
    "content": "import Graph from '../../../data-structures/graph/Graph';\nimport PriorityQueue from '../../../data-structures/priority-queue/PriorityQueue';\n\n/**\n * @param {Graph} graph\n * @return {Graph}\n */\nexport default function prim(graph) {\n  // It should fire error if graph is directed since the algorithm works only\n  // for undirected graphs.\n  if (graph.isDirected) {\n    throw new Error('Prim\\'s algorithms works only for undirected graphs');\n  }\n\n  // Init new graph that will contain minimum spanning tree of original graph.\n  const minimumSpanningTree = new Graph();\n\n  // This priority queue will contain all the edges that are starting from\n  // visited nodes and they will be ranked by edge weight - so that on each step\n  // we would always pick the edge with minimal edge weight.\n  const edgesQueue = new PriorityQueue();\n\n  // Set of vertices that has been already visited.\n  const visitedVertices = {};\n\n  // Vertex from which we will start graph traversal.\n  const startVertex = graph.getAllVertices()[0];\n\n  // Add start vertex to the set of visited ones.\n  visitedVertices[startVertex.getKey()] = startVertex;\n\n  // Add all edges of start vertex to the queue.\n  startVertex.getEdges().forEach((graphEdge) => {\n    edgesQueue.add(graphEdge, graphEdge.weight);\n  });\n\n  // Now let's explore all queued edges.\n  while (!edgesQueue.isEmpty()) {\n    // Fetch next queued edge with minimal weight.\n    /** @var {GraphEdge} currentEdge */\n    const currentMinEdge = edgesQueue.poll();\n\n    // Find out the next unvisited minimal vertex to traverse.\n    let nextMinVertex = null;\n    if (!visitedVertices[currentMinEdge.startVertex.getKey()]) {\n      nextMinVertex = currentMinEdge.startVertex;\n    } else if (!visitedVertices[currentMinEdge.endVertex.getKey()]) {\n      nextMinVertex = currentMinEdge.endVertex;\n    }\n\n    // If all vertices of current edge has been already visited then skip this round.\n    if (nextMinVertex) {\n      // Add current min edge to MST.\n      minimumSpanningTree.addEdge(currentMinEdge);\n\n      // Add vertex to the set of visited ones.\n      visitedVertices[nextMinVertex.getKey()] = nextMinVertex;\n\n      // Add all current vertex's edges to the queue.\n      nextMinVertex.getEdges().forEach((graphEdge) => {\n        // Add only vertices that link to unvisited nodes.\n        if (\n          !visitedVertices[graphEdge.startVertex.getKey()]\n          || !visitedVertices[graphEdge.endVertex.getKey()]\n        ) {\n          edgesQueue.add(graphEdge, graphEdge.weight);\n        }\n      });\n    }\n  }\n\n  return minimumSpanningTree;\n}\n"
  },
  {
    "path": "src/algorithms/graph/strongly-connected-components/README.md",
    "content": "# Strongly Connected Component\n\nA directed graph is called **strongly connected** if there is a path \nin each direction between each pair of vertices of the graph. \nIn a directed graph G that may not itself be strongly connected, \na pair of vertices `u` and `v` are said to be strongly connected \nto each other if there is a path in each direction between them.\n\n![Strongly Connected](https://upload.wikimedia.org/wikipedia/commons/5/5c/Scc.png)\n\nGraph with strongly connected components marked\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Strongly_connected_component)\n- [YouTube](https://www.youtube.com/watch?v=RpgcYiky7uw&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/strongly-connected-components/__test__/stronglyConnectedComponents.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport stronglyConnectedComponents from '../stronglyConnectedComponents';\n\ndescribe('stronglyConnectedComponents', () => {\n  it('should detect strongly connected components in simple graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCA = new GraphEdge(vertexC, vertexA);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n\n    const graph = new Graph(true);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCA)\n      .addEdge(edgeCD);\n\n    const components = stronglyConnectedComponents(graph);\n\n    expect(components).toBeDefined();\n    expect(components.length).toBe(2);\n\n    expect(components[0][0].getKey()).toBe(vertexA.getKey());\n    expect(components[0][1].getKey()).toBe(vertexC.getKey());\n    expect(components[0][2].getKey()).toBe(vertexB.getKey());\n\n    expect(components[1][0].getKey()).toBe(vertexD.getKey());\n  });\n\n  it('should detect strongly connected components in graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n    const vertexI = new GraphVertex('I');\n    const vertexJ = new GraphVertex('J');\n    const vertexK = new GraphVertex('K');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCA = new GraphEdge(vertexC, vertexA);\n    const edgeBD = new GraphEdge(vertexB, vertexD);\n    const edgeDE = new GraphEdge(vertexD, vertexE);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeFD = new GraphEdge(vertexF, vertexD);\n    const edgeGF = new GraphEdge(vertexG, vertexF);\n    const edgeGH = new GraphEdge(vertexG, vertexH);\n    const edgeHI = new GraphEdge(vertexH, vertexI);\n    const edgeIJ = new GraphEdge(vertexI, vertexJ);\n    const edgeJG = new GraphEdge(vertexJ, vertexG);\n    const edgeJK = new GraphEdge(vertexJ, vertexK);\n\n    const graph = new Graph(true);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCA)\n      .addEdge(edgeBD)\n      .addEdge(edgeDE)\n      .addEdge(edgeEF)\n      .addEdge(edgeFD)\n      .addEdge(edgeGF)\n      .addEdge(edgeGH)\n      .addEdge(edgeHI)\n      .addEdge(edgeIJ)\n      .addEdge(edgeJG)\n      .addEdge(edgeJK);\n\n    const components = stronglyConnectedComponents(graph);\n\n    expect(components).toBeDefined();\n    expect(components.length).toBe(4);\n\n    expect(components[0][0].getKey()).toBe(vertexG.getKey());\n    expect(components[0][1].getKey()).toBe(vertexJ.getKey());\n    expect(components[0][2].getKey()).toBe(vertexI.getKey());\n    expect(components[0][3].getKey()).toBe(vertexH.getKey());\n\n    expect(components[1][0].getKey()).toBe(vertexK.getKey());\n\n    expect(components[2][0].getKey()).toBe(vertexA.getKey());\n    expect(components[2][1].getKey()).toBe(vertexC.getKey());\n    expect(components[2][2].getKey()).toBe(vertexB.getKey());\n\n    expect(components[3][0].getKey()).toBe(vertexD.getKey());\n    expect(components[3][1].getKey()).toBe(vertexF.getKey());\n    expect(components[3][2].getKey()).toBe(vertexE.getKey());\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/strongly-connected-components/stronglyConnectedComponents.js",
    "content": "import Stack from '../../../data-structures/stack/Stack';\nimport depthFirstSearch from '../depth-first-search/depthFirstSearch';\n\n/**\n * @param {Graph} graph\n * @return {Stack}\n */\nfunction getVerticesSortedByDfsFinishTime(graph) {\n  // Set of all visited vertices during DFS pass.\n  const visitedVerticesSet = {};\n\n  // Stack of vertices by finish time.\n  // All vertices in this stack are ordered by finished time in decreasing order.\n  // Vertex that has been finished first will be at the bottom of the stack and\n  // vertex that has been finished last will be at the top of the stack.\n  const verticesByDfsFinishTime = new Stack();\n\n  // Set of all vertices we're going to visit.\n  const notVisitedVerticesSet = {};\n  graph.getAllVertices().forEach((vertex) => {\n    notVisitedVerticesSet[vertex.getKey()] = vertex;\n  });\n\n  // Specify DFS traversal callbacks.\n  const dfsCallbacks = {\n    enterVertex: ({ currentVertex }) => {\n      // Add current vertex to visited set.\n      visitedVerticesSet[currentVertex.getKey()] = currentVertex;\n\n      // Delete current vertex from not visited set.\n      delete notVisitedVerticesSet[currentVertex.getKey()];\n    },\n    leaveVertex: ({ currentVertex }) => {\n      // Push vertex to the stack when leaving it.\n      // This will make stack to be ordered by finish time in decreasing order.\n      verticesByDfsFinishTime.push(currentVertex);\n    },\n    allowTraversal: ({ nextVertex }) => {\n      // Don't allow to traverse the nodes that have been already visited.\n      return !visitedVerticesSet[nextVertex.getKey()];\n    },\n  };\n\n  // Do FIRST DFS PASS traversal for all graph vertices to fill the verticesByFinishTime stack.\n  while (Object.values(notVisitedVerticesSet).length) {\n    // Peek any vertex to start DFS traversal from.\n    const startVertexKey = Object.keys(notVisitedVerticesSet)[0];\n    const startVertex = notVisitedVerticesSet[startVertexKey];\n    delete notVisitedVerticesSet[startVertexKey];\n\n    depthFirstSearch(graph, startVertex, dfsCallbacks);\n  }\n\n  return verticesByDfsFinishTime;\n}\n\n/**\n * @param {Graph} graph\n * @param {Stack} verticesByFinishTime\n * @return {*[]}\n */\nfunction getSCCSets(graph, verticesByFinishTime) {\n  // Array of arrays of strongly connected vertices.\n  const stronglyConnectedComponentsSets = [];\n\n  // Array that will hold all vertices that are being visited during one DFS run.\n  let stronglyConnectedComponentsSet = [];\n\n  // Visited vertices set.\n  const visitedVerticesSet = {};\n\n  // Callbacks for DFS traversal.\n  const dfsCallbacks = {\n    enterVertex: ({ currentVertex }) => {\n      // Add current vertex to SCC set of current DFS round.\n      stronglyConnectedComponentsSet.push(currentVertex);\n\n      // Add current vertex to visited set.\n      visitedVerticesSet[currentVertex.getKey()] = currentVertex;\n    },\n    leaveVertex: ({ previousVertex }) => {\n      // Once DFS traversal is finished push the set of found strongly connected\n      // components during current DFS round to overall strongly connected components set.\n      // The sign that traversal is about to be finished is that we came back to start vertex\n      // which doesn't have parent.\n      if (previousVertex === null) {\n        stronglyConnectedComponentsSets.push([...stronglyConnectedComponentsSet]);\n      }\n    },\n    allowTraversal: ({ nextVertex }) => {\n      // Don't allow traversal of already visited vertices.\n      return !visitedVerticesSet[nextVertex.getKey()];\n    },\n  };\n\n  while (!verticesByFinishTime.isEmpty()) {\n    /** @var {GraphVertex} startVertex */\n    const startVertex = verticesByFinishTime.pop();\n\n    // Reset the set of strongly connected vertices.\n    stronglyConnectedComponentsSet = [];\n\n    // Don't do DFS on already visited vertices.\n    if (!visitedVerticesSet[startVertex.getKey()]) {\n      // Do DFS traversal.\n      depthFirstSearch(graph, startVertex, dfsCallbacks);\n    }\n  }\n\n  return stronglyConnectedComponentsSets;\n}\n\n/**\n * Kosaraju's algorithm.\n *\n * @param {Graph} graph\n * @return {*[]}\n */\nexport default function stronglyConnectedComponents(graph) {\n  // In this algorithm we will need to do TWO DFS PASSES overt the graph.\n\n  // Get stack of vertices ordered by DFS finish time.\n  // All vertices in this stack are ordered by finished time in decreasing order:\n  // Vertex that has been finished first will be at the bottom of the stack and\n  // vertex that has been finished last will be at the top of the stack.\n  const verticesByFinishTime = getVerticesSortedByDfsFinishTime(graph);\n\n  // Reverse the graph.\n  graph.reverse();\n\n  // Do DFS once again on reversed graph.\n  return getSCCSets(graph, verticesByFinishTime);\n}\n"
  },
  {
    "path": "src/algorithms/graph/topological-sorting/README.md",
    "content": "# Topological Sorting\n\nIn the field of computer science, a topological sort or \ntopological ordering of a directed graph is a linear ordering \nof its vertices such that for every directed edge `uv` from \nvertex `u` to vertex `v`, `u` comes before `v` in the ordering.\n\nFor instance, the vertices of the graph may represent tasks to \nbe performed, and the edges may represent constraints that one \ntask must be performed before another; in this application, a \ntopological ordering is just a valid sequence for the tasks.\n\nA topological ordering is possible if and only if the graph has\nno directed cycles, that is, if it is a [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) \n(DAG). Any DAG has at least one topological ordering, and algorithms are \nknown for constructing a topological ordering of any DAG in linear time.\n\n![Directed Acyclic Graph](https://upload.wikimedia.org/wikipedia/commons/c/c6/Topological_Ordering.svg)\n\nA topological ordering of a directed acyclic graph: every edge goes from \nearlier in the ordering (upper left) to later in the ordering (lower right). \nA directed graph is acyclic if and only if it has a topological ordering.\n\n## Example\n\n![Topologic Sorting](https://upload.wikimedia.org/wikipedia/commons/0/03/Directed_acyclic_graph_2.svg)\n\nThe graph shown above has many valid topological sorts, including:\n\n- `5, 7, 3, 11, 8, 2, 9, 10` (visual left-to-right, top-to-bottom)\n- `3, 5, 7, 8, 11, 2, 9, 10` (smallest-numbered available vertex first)\n- `5, 7, 3, 8, 11, 10, 9, 2` (fewest edges first)\n- `7, 5, 11, 3, 10, 8, 9, 2` (largest-numbered available vertex first)\n- `5, 7, 11, 2, 3, 8, 9, 10` (attempting top-to-bottom, left-to-right)\n- `3, 7, 8, 5, 11, 10, 2, 9` (arbitrary)\n\n## Application\n\nThe canonical application of topological sorting is in \n**scheduling a sequence of jobs** or tasks based on their dependencies. The jobs \nare represented by vertices, and there is an edge from `x` to `y` if \njob `x` must be completed before job `y` can be started (for \nexample, when washing clothes, the washing machine must finish \nbefore we put the clothes in the dryer). Then, a topological sort \ngives an order in which to perform the jobs.\n\nOther application is **dependency resolution**. Each vertex is a package\nand each edge is a dependency of package `a` on package 'b'. Then topological\nsorting will provide a sequence of installing dependencies in a way that every\nnext dependency has its dependent packages to be installed in prior.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Topological_sorting)\n- [Topological Sorting on YouTube by Tushar Roy](https://www.youtube.com/watch?v=ddTC4Zovtbc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/graph/topological-sorting/__test__/topologicalSort.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport topologicalSort from '../topologicalSort';\n\ndescribe('topologicalSort', () => {\n  it('should do topological sorting on graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n    const vertexE = new GraphVertex('E');\n    const vertexF = new GraphVertex('F');\n    const vertexG = new GraphVertex('G');\n    const vertexH = new GraphVertex('H');\n\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeBD = new GraphEdge(vertexB, vertexD);\n    const edgeCE = new GraphEdge(vertexC, vertexE);\n    const edgeDF = new GraphEdge(vertexD, vertexF);\n    const edgeEF = new GraphEdge(vertexE, vertexF);\n    const edgeEH = new GraphEdge(vertexE, vertexH);\n    const edgeFG = new GraphEdge(vertexF, vertexG);\n\n    const graph = new Graph(true);\n\n    graph\n      .addEdge(edgeAC)\n      .addEdge(edgeBC)\n      .addEdge(edgeBD)\n      .addEdge(edgeCE)\n      .addEdge(edgeDF)\n      .addEdge(edgeEF)\n      .addEdge(edgeEH)\n      .addEdge(edgeFG);\n\n    const sortedVertices = topologicalSort(graph);\n\n    expect(sortedVertices).toBeDefined();\n    expect(sortedVertices.length).toBe(graph.getAllVertices().length);\n    expect(sortedVertices).toEqual([\n      vertexB,\n      vertexD,\n      vertexA,\n      vertexC,\n      vertexE,\n      vertexH,\n      vertexF,\n      vertexG,\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/topological-sorting/topologicalSort.js",
    "content": "import Stack from '../../../data-structures/stack/Stack';\nimport depthFirstSearch from '../depth-first-search/depthFirstSearch';\n\n/**\n * @param {Graph} graph\n */\nexport default function topologicalSort(graph) {\n  // Create a set of all vertices we want to visit.\n  const unvisitedSet = {};\n  graph.getAllVertices().forEach((vertex) => {\n    unvisitedSet[vertex.getKey()] = vertex;\n  });\n\n  // Create a set for all vertices that we've already visited.\n  const visitedSet = {};\n\n  // Create a stack of already ordered vertices.\n  const sortedStack = new Stack();\n\n  const dfsCallbacks = {\n    enterVertex: ({ currentVertex }) => {\n      // Add vertex to visited set in case if all its children has been explored.\n      visitedSet[currentVertex.getKey()] = currentVertex;\n\n      // Remove this vertex from unvisited set.\n      delete unvisitedSet[currentVertex.getKey()];\n    },\n    leaveVertex: ({ currentVertex }) => {\n      // If the vertex has been totally explored then we may push it to stack.\n      sortedStack.push(currentVertex);\n    },\n    allowTraversal: ({ nextVertex }) => {\n      return !visitedSet[nextVertex.getKey()];\n    },\n  };\n\n  // Let's go and do DFS for all unvisited nodes.\n  while (Object.keys(unvisitedSet).length) {\n    const currentVertexKey = Object.keys(unvisitedSet)[0];\n    const currentVertex = unvisitedSet[currentVertexKey];\n\n    // Do DFS for current node.\n    depthFirstSearch(graph, currentVertex, dfsCallbacks);\n  }\n\n  return sortedStack.toArray();\n}\n"
  },
  {
    "path": "src/algorithms/graph/travelling-salesman/README.md",
    "content": "# Travelling Salesman Problem\n\nThe travelling salesman problem (TSP) asks the following question: \n\"Given a list of cities and the distances between each pair of \ncities, what is the shortest possible route that visits each city \nand returns to the origin city?\"\n\n![Travelling Salesman](https://upload.wikimedia.org/wikipedia/commons/1/11/GLPK_solution_of_a_travelling_salesman_problem.svg)\n\nSolution of a travelling salesman problem: the black line shows \nthe shortest possible loop that connects every red dot.\n\n![Travelling Salesman Graph](https://upload.wikimedia.org/wikipedia/commons/3/30/Weighted_K4.svg)\n\nTSP can be modelled as an undirected weighted graph, such that \ncities are the graph's vertices, paths are the graph's edges, \nand a path's distance is the edge's weight. It is a minimization \nproblem starting and finishing at a specified vertex after having \nvisited each other vertex exactly once. Often, the model is a \ncomplete graph (i.e. each pair of vertices is connected by an \nedge). If no path exists between two cities, adding an arbitrarily \nlong edge will complete the graph without affecting the optimal tour.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Travelling_salesman_problem)\n"
  },
  {
    "path": "src/algorithms/graph/travelling-salesman/__test__/bfTravellingSalesman.test.js",
    "content": "import GraphVertex from '../../../../data-structures/graph/GraphVertex';\nimport GraphEdge from '../../../../data-structures/graph/GraphEdge';\nimport Graph from '../../../../data-structures/graph/Graph';\nimport bfTravellingSalesman from '../bfTravellingSalesman';\n\ndescribe('bfTravellingSalesman', () => {\n  it('should solve problem for simple graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 1);\n    const edgeBD = new GraphEdge(vertexB, vertexD, 1);\n    const edgeDC = new GraphEdge(vertexD, vertexC, 1);\n    const edgeCA = new GraphEdge(vertexC, vertexA, 1);\n\n    const edgeBA = new GraphEdge(vertexB, vertexA, 5);\n    const edgeDB = new GraphEdge(vertexD, vertexB, 8);\n    const edgeCD = new GraphEdge(vertexC, vertexD, 7);\n    const edgeAC = new GraphEdge(vertexA, vertexC, 4);\n    const edgeAD = new GraphEdge(vertexA, vertexD, 2);\n    const edgeDA = new GraphEdge(vertexD, vertexA, 3);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 3);\n    const edgeCB = new GraphEdge(vertexC, vertexB, 9);\n\n    const graph = new Graph(true);\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBD)\n      .addEdge(edgeDC)\n      .addEdge(edgeCA)\n      .addEdge(edgeBA)\n      .addEdge(edgeDB)\n      .addEdge(edgeCD)\n      .addEdge(edgeAC)\n      .addEdge(edgeAD)\n      .addEdge(edgeDA)\n      .addEdge(edgeBC)\n      .addEdge(edgeCB);\n\n    const salesmanPath = bfTravellingSalesman(graph);\n\n    expect(salesmanPath.length).toBe(4);\n\n    expect(salesmanPath[0].getKey()).toEqual(vertexA.getKey());\n    expect(salesmanPath[1].getKey()).toEqual(vertexB.getKey());\n    expect(salesmanPath[2].getKey()).toEqual(vertexD.getKey());\n    expect(salesmanPath[3].getKey()).toEqual(vertexC.getKey());\n  });\n});\n"
  },
  {
    "path": "src/algorithms/graph/travelling-salesman/bfTravellingSalesman.js",
    "content": "/**\n * Get all possible paths\n * @param {GraphVertex} startVertex\n * @param {GraphVertex[][]} [paths]\n * @param {GraphVertex[]} [path]\n */\nfunction findAllPaths(startVertex, paths = [], path = []) {\n  // Clone path.\n  const currentPath = [...path];\n\n  // Add startVertex to the path.\n  currentPath.push(startVertex);\n\n  // Generate visited set from path.\n  const visitedSet = currentPath.reduce((accumulator, vertex) => {\n    const updatedAccumulator = { ...accumulator };\n    updatedAccumulator[vertex.getKey()] = vertex;\n\n    return updatedAccumulator;\n  }, {});\n\n  // Get all unvisited neighbors of startVertex.\n  const unvisitedNeighbors = startVertex.getNeighbors().filter((neighbor) => {\n    return !visitedSet[neighbor.getKey()];\n  });\n\n  // If there no unvisited neighbors then treat current path as complete and save it.\n  if (!unvisitedNeighbors.length) {\n    paths.push(currentPath);\n\n    return paths;\n  }\n\n  // Go through all the neighbors.\n  for (let neighborIndex = 0; neighborIndex < unvisitedNeighbors.length; neighborIndex += 1) {\n    const currentUnvisitedNeighbor = unvisitedNeighbors[neighborIndex];\n    findAllPaths(currentUnvisitedNeighbor, paths, currentPath);\n  }\n\n  return paths;\n}\n\n/**\n * @param {number[][]} adjacencyMatrix\n * @param {object} verticesIndices\n * @param {GraphVertex[]} cycle\n * @return {number}\n */\nfunction getCycleWeight(adjacencyMatrix, verticesIndices, cycle) {\n  let weight = 0;\n\n  for (let cycleIndex = 1; cycleIndex < cycle.length; cycleIndex += 1) {\n    const fromVertex = cycle[cycleIndex - 1];\n    const toVertex = cycle[cycleIndex];\n    const fromVertexIndex = verticesIndices[fromVertex.getKey()];\n    const toVertexIndex = verticesIndices[toVertex.getKey()];\n    weight += adjacencyMatrix[fromVertexIndex][toVertexIndex];\n  }\n\n  return weight;\n}\n\n/**\n * BRUTE FORCE approach to solve Traveling Salesman Problem.\n *\n * @param {Graph} graph\n * @return {GraphVertex[]}\n */\nexport default function bfTravellingSalesman(graph) {\n  // Pick starting point from where we will traverse the graph.\n  const startVertex = graph.getAllVertices()[0];\n\n  // BRUTE FORCE.\n  // Generate all possible paths from startVertex.\n  const allPossiblePaths = findAllPaths(startVertex);\n\n  // Filter out paths that are not cycles.\n  const allPossibleCycles = allPossiblePaths.filter((path) => {\n    /** @var {GraphVertex} */\n    const lastVertex = path[path.length - 1];\n    const lastVertexNeighbors = lastVertex.getNeighbors();\n\n    return lastVertexNeighbors.includes(startVertex);\n  });\n\n  // Go through all possible cycles and pick the one with minimum overall tour weight.\n  const adjacencyMatrix = graph.getAdjacencyMatrix();\n  const verticesIndices = graph.getVerticesIndices();\n  let salesmanPath = [];\n  let salesmanPathWeight = null;\n  for (let cycleIndex = 0; cycleIndex < allPossibleCycles.length; cycleIndex += 1) {\n    const currentCycle = allPossibleCycles[cycleIndex];\n    const currentCycleWeight = getCycleWeight(adjacencyMatrix, verticesIndices, currentCycle);\n\n    // If current cycle weight is smaller then previous ones treat current cycle as most optimal.\n    if (salesmanPathWeight === null || currentCycleWeight < salesmanPathWeight) {\n      salesmanPath = currentCycle;\n      salesmanPathWeight = currentCycleWeight;\n    }\n  }\n\n  // Return the solution.\n  return salesmanPath;\n}\n"
  },
  {
    "path": "src/algorithms/image-processing/seam-carving/README.md",
    "content": "# Content-aware image resizing in JavaScript\n\n![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)\n\n> 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.\n\n## TL;DR\n\nThere 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.\n\nSo, with this article I want to do three things:\n\n1. Provide you with an interactive **content-aware resizer** so that you could play around with resizing your own images\n2. Explain the idea behind the **Seam Carving algorithm**\n3. Explain the **dynamic programming approach** to implement the algorithm (we'll be using TypeScript for it)\n\n### Content-aware image resizing\n\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*.\n\nThe 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.\n\n![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)\n\nThe 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.\n\n![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)\n\nFinding 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).\n\n### Objects removal\n\nThe 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.\n\n![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)\n\n### JS IMAGE CARVER demo\n\nI'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.\n\n### More examples\n\nHere are some more examples of how the algorithm copes with more complex backgrounds.\n\nMountains on the background are being shrunk smoothly without visible seams.\n\n![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)\n\nThe same goes for the ocean waves. The algorithm preserved the wave structure without distorting the surfers.\n\n![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)\n\nWe 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.\n\n![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)\n\n## How Seam Carving algorithms works\n\nImagine 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:\n\n- *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).\n- *Preserve the proportions* of the important parts of the image (i.e. circle car wheels should not be squeezed to the ellipse wheels)\n\nTo 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.\n\nThe 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.\n\n![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)\n\nAssuming 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):\n\n![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)\n\nWhere:\n\n- `mEnergy` - *Energy* (importance) of the *middle* pixel (`[0..626]` if rounded)\n- `lR` - *Red* channel value for the *left* pixel (`[0..255]`)\n- `mR` - *Red* channel value for the *middle* pixel (`[0..255]`)\n- `rR` - *Red* channel value for the *right* pixel (`[0..255]`)\n- `lG` - *Green* channel value for the *left* pixel (`[0..255]`)\n- and so on...\n\nIn 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.\n\n![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)\n\nNow, 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.\n\nFor 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.\n\nThe 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\nTo 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.\n\n![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)\n\nHere is a real example of the energy map for the demo image you saw above (with hot air balloons).\n\n![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)\n\nYou 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/).\n\nWe 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.\n\n![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)\n\nFinding 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.\n\nIn the example below, you may see the energy map with the first lowest energy seam that was found for it.\n\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)\n\nIn 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:\n\n- start using *top* and *bottom* pixel neighbors (instead of *left* and *right* ones) to calculate the pixel energy\n- when searching for a seam we need to move from *left* to *right* (instead of from *up* to *bottom*)\n\n## Implementation in TypeScript\n\n> You may find the source code, and the functions mentioned below in the [js-image-carver](https://github.com/trekhleb/js-image-carver) repository.\n\nTo implement the algorithm we will be using TypeScript. If you want a JavaScript version, you may ignore (remove) type definitions and their usages.\n\nFor simplicity reasons let's implement the seam carving algorithm only for the image *width* reduction.\n\n### Content-aware width resizing (the entry function)\n\nFirst, let's define some common types that we're going to use while implementing the algorithm.\n\n```typescript\n// Type that describes the image size (width and height).\ntype ImageSize = { w: number, h: number };\n\n// The coordinate of the pixel.\ntype Coordinate = { x: number, y: number };\n\n// The seam is a sequence of pixels (coordinates).\ntype Seam = Coordinate[];\n\n// Energy map is a 2D array that has the same width and height\n// as the image the map is being calculated for.\ntype EnergyMap = number[][];\n\n// Type that describes the image pixel's RGBA color.\ntype Color = [\n  r: number, // Red\n  g: number, // Green\n  b: number, // Blue\n  a: number, // Alpha (transparency)\n] | Uint8ClampedArray;\n```\n\nOn the high level the algorithm consists of the following steps:\n\n1. Calculate the **energy map** for the current version of the image.\n2. Find the **seam** with the lowest energy based on the energy map (this is where we will apply Dynamic Programming).\n3. **Delete the seam** with the lowest energy seam from the image.\n4. **Repeat** until the image width is reduced to the desired value.\n\n```typescript\ntype ResizeImageWidthArgs = {\n  img: ImageData, // Image data we want to resize.\n  toWidth: number, // Final image width we want the image to shrink to.\n};\n\ntype ResizeImageWidthResult = {\n  img: ImageData, // Resized image data.\n  size: ImageSize, // Resized image size (w x h).\n};\n\n// Performs the content-aware image width resizing using the seam carving method.\nexport const resizeImageWidth = (\n  { img, toWidth }: ResizeImageWidthArgs,\n): ResizeImageWidthResult => {\n  // For performance reasons we want to avoid changing the img data array size.\n  // Instead we'll just keep the record of the resized image width and height separately.\n  const size: ImageSize = { w: img.width, h: img.height };\n\n  // Calculating the number of pixels to remove.\n  const pxToRemove = img.width - toWidth;\n  if (pxToRemove < 0) {\n    throw new Error('Upsizing is not supported for now');\n  }\n\n  let energyMap: EnergyMap | null = null;\n  let seam: Seam | null = null;\n\n  // Removing the lowest energy seams one by one.\n  for (let i = 0; i < pxToRemove; i += 1) {\n    // 1. Calculate the energy map for the current version of the image.\n    energyMap = calculateEnergyMap(img, size);\n\n    // 2. Find the seam with the lowest energy based on the energy map.\n    seam = findLowEnergySeam(energyMap, size);\n\n    // 3. Delete the seam with the lowest energy seam from the image.\n    deleteSeam(img, seam, size);\n\n    // Reduce the image width, and continue iterations.\n    size.w -= 1;\n  }\n\n  // Returning the resized image and its final size.\n  // The img is actually a reference to the ImageData, so technically\n  // the caller of the function already has this pointer. But let's\n  // still return it for better code readability.\n  return { img, size };\n};\n```\n\nThe 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:\n\n```javascript\nconst ctx = canvas.getContext('2d');\nconst imgData = ctx.getImageData(0, 0, imgWidth, imgHeight);\n```\n\n> 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.\n\nLet's break down each step ony be one and implement the `calculateEnergyMap()`, `findLowEnergySeam()` and `deleteSeam()` functions.\n\n### Calculating the pixel's energy\n\nHere 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.\n\n```typescript\n// Calculates the energy of a pixel.\nconst getPixelEnergy = (left: Color | null, middle: Color, right: Color | null): number => {\n  // Middle pixel is the pixel we're calculating the energy for.\n  const [mR, mG, mB] = middle;\n\n  // Energy from the left pixel (if it exists).\n  let lEnergy = 0;\n  if (left) {\n    const [lR, lG, lB] = left;\n    lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2;\n  }\n\n  // Energy from the right pixel (if it exists).\n  let rEnergy = 0;\n  if (right) {\n    const [rR, rG, rB] = right;\n    rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2;\n  }\n\n  // Resulting pixel energy.\n  return Math.sqrt(lEnergy + rEnergy);\n};\n```\n\n### Calculating the energy map\n\nThe 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.\n\n```typescript\n// Helper function that returns the color of the pixel.\nconst getPixel = (img: ImageData, { x, y }: Coordinate): Color => {\n  // The ImageData data array is a flat 1D array.\n  // Thus we need to convert x and y coordinates to the linear index.\n  const i = y * img.width + x;\n  const cellsPerColor = 4; // RGBA\n  // For better efficiency, instead of creating a new sub-array we return\n  // a pointer to the part of the ImageData array.\n  return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor);\n};\n\n// Helper function that sets the color of the pixel.\nconst setPixel = (img: ImageData, { x, y }: Coordinate, color: Color): void => {\n  // The ImageData data array is a flat 1D array.\n  // Thus we need to convert x and y coordinates to the linear index.\n  const i = y * img.width + x;\n  const cellsPerColor = 4; // RGBA\n  img.data.set(color, i * cellsPerColor);\n};\n```\n\nTo calculate the energy map we go through each image pixel and call the previously described `getPixelEnergy()` function against it.\n\n```typescript\n// Helper function that creates a matrix (2D array) of specific\n// size (w x h) and fills it with specified value.\nconst matrix = <T>(w: number, h: number, filler: T): T[][] => {\n  return new Array(h)\n    .fill(null)\n    .map(() => {\n      return new Array(w).fill(filler);\n    });\n};\n\n// Calculates the energy of each pixel of the image.\nconst calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => {\n  // Create an empty energy map where each pixel has infinitely high energy.\n  // We will update the energy of each pixel.\n  const energyMap: number[][] = matrix<number>(w, h, Infinity);\n  for (let y = 0; y < h; y += 1) {\n    for (let x = 0; x < w; x += 1) {\n      // Left pixel might not exist if we're on the very left edge of the image.\n      const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null;\n      // The color of the middle pixel that we're calculating the energy for.\n      const middle = getPixel(img, { x, y });\n      // Right pixel might not exist if we're on the very right edge of the image.\n      const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null;\n      energyMap[y][x] = getPixelEnergy(left, middle, right);\n    }\n  }\n  return energyMap;\n};\n```\n\n> 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.\n\n### Finding the seam with the lowest energy (Dynamic Programming approach)\n\n> 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.\n\nThe 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.\n\n#### The naive approach\n\nThe naive approach would be to check all possible paths one after another.\n\n![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)\n\nGoing 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.\n\n#### The greedy approach\n\nWe 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.\n\n![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)\n\nThis 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.\n\nThe 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).\n\n#### The dynamic programming approach\n\nYou 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.\n\n![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)\n\nIn 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`.\n\n> 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.\n\nSo, 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).\n\nLet'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.\n\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)\n\nSince 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.\n\n![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)\n\nIn general, we have three possible previous seems to choose from:\n\n![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\nYou may think about it this way:\n\n- 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]`\n- **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)`\n\nIf we fill the `seamsEnergies` table completely, then the minimum number in the lowest row would be the lowest possible seam energy.\n\nLet's try to fill several cells of this table to see how it works.\n\n![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)\n\nAfter 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.\n\nThe 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.\n\nHere is an example of how this logic might be implemented:\n\n```typescript\n// The metadata for the pixels in the seam.\ntype SeamPixelMeta = {\n  energy: number, // The energy of the pixel.\n  coordinate: Coordinate, // The coordinate of the pixel.\n  previous: Coordinate | null, // The previous pixel in a seam.\n};\n\n// Finds the seam (the sequence of pixels from top to bottom) that has the\n// lowest resulting energy using the Dynamic Programming approach.\nconst findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {\n  // The 2D array of the size of w and h, where each pixel contains the\n  // seam metadata (pixel energy, pixel coordinate and previous pixel from\n  // the lowest energy seam at this point).\n  const seamsEnergies: (SeamPixelMeta | null)[][] = matrix<SeamPixelMeta | null>(w, h, null);\n\n  // Populate the first row of the map by just copying the energies\n  // from the energy map.\n  for (let x = 0; x < w; x += 1) {\n    const y = 0;\n    seamsEnergies[y][x] = {\n      energy: energyMap[y][x],\n      coordinate: { x, y },\n      previous: null,\n    };\n  }\n\n  // Populate the rest of the rows.\n  for (let y = 1; y < h; y += 1) {\n    for (let x = 0; x < w; x += 1) {\n      // Find the top adjacent cell with minimum energy.\n      // This cell would be the tail of a seam with lowest energy at this point.\n      // It doesn't mean that this seam (path) has lowest energy globally.\n      // Instead, it means that we found a path with the lowest energy that may lead\n      // us to the current pixel with the coordinates x and y.\n      let minPrevEnergy = Infinity;\n      let minPrevX: number = x;\n      for (let i = (x - 1); i <= (x + 1); i += 1) {\n        if (i >= 0 && i < w && seamsEnergies[y - 1][i].energy < minPrevEnergy) {\n          minPrevEnergy = seamsEnergies[y - 1][i].energy;\n          minPrevX = i;\n        }\n      }\n\n      // Update the current cell.\n      seamsEnergies[y][x] = {\n        energy: minPrevEnergy + energyMap[y][x],\n        coordinate: { x, y },\n        previous: { x: minPrevX, y: y - 1 },\n      };\n    }\n  }\n\n  // Find where the minimum energy seam ends.\n  // We need to find the tail of the lowest energy seam to start\n  // traversing it from its tail to its head (from the bottom to the top).\n  let lastMinCoordinate: Coordinate | null = null;\n  let minSeamEnergy = Infinity;\n  for (let x = 0; x < w; x += 1) {\n    const y = h - 1;\n    if (seamsEnergies[y][x].energy < minSeamEnergy) {\n      minSeamEnergy = seamsEnergies[y][x].energy;\n      lastMinCoordinate = { x, y };\n    }\n  }\n\n  // Find the lowest energy energy seam.\n  // Once we know where the tail is we may traverse and assemble the lowest\n  // energy seam based on the \"previous\" value of the seam pixel metadata.\n  const seam: Seam = [];\n  if (!lastMinCoordinate) {\n    return seam;\n  }\n\n  const { x: lastMinX, y: lastMinY } = lastMinCoordinate;\n\n  // Adding new pixel to the seam path one by one until we reach the top.\n  let currentSeam = seamsEnergies[lastMinY][lastMinX];\n  while (currentSeam) {\n    seam.push(currentSeam.coordinate);\n    const prevMinCoordinates = currentSeam.previous;\n    if (!prevMinCoordinates) {\n      currentSeam = null;\n    } else {\n      const { x: prevMinX, y: prevMinY } = prevMinCoordinates;\n      currentSeam = seamsEnergies[prevMinY][prevMinX];\n    }\n  }\n\n  return seam;\n};\n```\n\n### Removing the seam with the lowest energy\n\nOnce 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.\n\n![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)\n\n```typescript\n// Deletes the seam from the image data.\n// We delete the pixel in each row and then shift the rest of the row pixels to the left.\nconst deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => {\n  seam.forEach(({ x: seamX, y: seamY }: Coordinate) => {\n    for (let x = seamX; x < (w - 1); x += 1) {\n      const nextPixel = getPixel(img, { x: x + 1, y: seamY });\n      setPixel(img, { x, y: seamY }, nextPixel);\n    }\n  });\n};\n```\n\n## Objects removal\n\nThe 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.\n\nCurrently, 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.\n\nHere is how the algorithm works for object removal.\n\n![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)\n\n## Issues and what's next\n\nThe [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.\n\nThe [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**.\n\nAnother interesting area of experimentation might be to make the algorithm work in a **real-time**.\n\n> 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.\n>\n> So, good luck with your own experiments!\n"
  },
  {
    "path": "src/algorithms/image-processing/seam-carving/README.ru-RU.md",
    "content": "# Изменение размеров изображения с учетом его содержимого в JavaScript\n\n![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)\n\n> Доступна [английская интерактивная версия этой статьи](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/) в которой вы можете загрузить свои собственные изображения и посмотреть, как алгоритм \"справляется\" с ними.\n\n## TL;DR\n\nНаписано много замечательных статей об алгоритме *Seam Carving* (\"Вырезание швов\"), но я не смог устоять перед соблазном самостоятельно исследовать этот элегантный, мощный и в то же время простой алгоритм и написать о своем личном опыте работы с ним. Мое внимание также привлек тот факт, что для его имплементации мы можем применить *динамическое программирование (DP)*. И, если вы, как и я, все еще находитесь на пути изучения алгоритмов, то это решение может обогатить ваш личный арсенал DP.\n\nИтак, в этой статье я хочу сделать три вещи:\n\n1. Предоставить вам возможность \"поиграться\" с алгоритмом самостоятельно при помощи **интерактивного ресайзера**.\n2. Объяснить **идею алгоритма Seam Carving**.\n3. Объяснить как можно **применить динамическое программирование** для имплементации алгоритма (мы будем писать на TypeScript).\n\n### Изменение размеров изображений с учетом их содержимого\n\n*Изменение размера изображения с учетом содержимого* (content-aware image resizing) может быть применено, когда дело доходит до изменения пропорций изображения (например, уменьшения ширины при сохранении высоты), а также когда потеря некоторых частей изображения нежелательна. Простое масштабирование изображения в этом случае исказит находящиеся в нем объекты. Для сохранения пропорций объектов при изменении пропорций изображения можно использовать [алгоритм Seam Carving](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf), который был описан *Shai Avidan* и *Ariel Shamir*.\n\nВ приведенном ниже примере показано, как ширина исходного изображения была уменьшена на 50% *с учетом содержимого изображения* (слева) и *без учета содержимого изображения* (справа, простой скейлинг). В данном случае левое изображение выглядит более естественным, так как пропорции воздушных шаров в нем были сохранены.\n\n![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)\n\nИдея алгоритма Seam Carving заключается в том, чтобы найти *шов* (seam, непрерывную последовательность пикселей) с наименьшим влиянием на содержание изображения, а затем его *вырезать* (carve). Этот процесс повторяется снова и снова, пока мы не получим требуемую ширину или высоту изображения. В примере ниже интуитивно видно, что пиксели воздушных шаров вносят больший \"вклад\" в содержание и смысл изображения, чем пиксели неба. Таким образом, сначала удаляются пиксели неба.\n\n![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)\n\nПоиск шва с наименьшей энергией (с наименьшим вкладом в содержимое изображения) является вычислительно дорогостоящей операцией (особенно для больших изображений). Для ускорения поиска шва может быть применено *динамическое программирование* (мы рассмотрим детали реализации ниже).\n\n### Удаление объектов\n\nВажность каждого пикселя (так называемая энергия пикселя) вычисляется исходя из его цветовой разницы (`R`, `G`, `B`, `A`) между двумя соседними пикселями. Если же мы вручную зададим некоторым пикселям низкий уровень энергии (например нарисовав маску поверх них), то алгоритм Seam Carving выполнит для нас **удаление помеченного объекта**, как говорится, \"забесплатно\".\n\n![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)\n\n### Интерактивный ресзайзер\n\nДля этой статьи я создал приложение [JS IMAGE CARVER](https://trekhleb.dev/js-image-carver/) (доступен также и [исходный код на GitHub](https://github.com/trekhleb/js-image-carver)), которым вы можете воспользоваться для ресайза своих изображений и увидеть в реальном времени, как работает алгоритм.\n\n### Другие примеры ресайза\n\nВот еще несколько примеров того, как алгоритм справляется с более сложным фоном.\n\nГоры на заднем плане плавно сжимаются, без видимых швов.\n\n![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)\n\nТо же самое и с океанскими волнами. Алгоритм сохранил волновую структуру, не искажая серферов.\n\n![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)\n\nНужно помнить, что алгоритм Seam Carving не является \"волшебной таблеткой\", и может не сохранить пропорции важных частей изображения в том случае, когда *большая часть пикселей выглядят как края, ребра или границы* (почти все пиксели выглядят одинаково важными с точки зрения алгоритма). В приведенном ниже примере изменение размера изображения с учетом содержимого похоже на простое масштабирование, т.к. для алгоритма все пиксели выглядят важными, и ему трудно отличить лицо Ван Гога от фона.\n\n![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)\n\n## Как работает алгоритм Seam Carving\n\nПредставим, что у нас есть картинка размером `1000 x 500 px`, и мы хотим уменьшить ее до `500 x 500 px` (допустим, квадратное изображение больше подходит для Instagram). В этом случае мы, возможно, захотим задать несколько **требований к процессу изменения размера**:\n\n- *Важные части изображения должны быть сохранены* (если до ресайза на фото было 5 деревьев, то и после ресайза мы хотим увидеть все те же 5 деревьев).\n- *Пропорции важных частей изображения должны быть сохранены* (круглые колеса автомобиля не должны стать овальными после ресайза).\n\nЧтобы избежать изменения важных частей изображения можно найти **непрерывную последовательность пикселей (шов)**, которая будет идти от верхней границы к нижней и иметь *наименьший вклад в содержимое* изображения (шов, который не проходит через важные части изображения), а затем удалить его. Удаление шва сожмет изображение на один пиксель. Далее надо повторять этот шаг до тех пор, пока изображение не станет нужной ширины.\n\nВопрос в том, как определить *важность пикселя* и его вклад в содержание изображения (в оригинальной статье авторы используют термин **энергия пикселя**). Один из способов это сделать — рассматривать все пиксели, образующие края (границы, ребра), как важные. В случае, если пиксель является частью ребра, его цвет будет отличаться от соседей (левого и правого пикселей).\n\n![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)\n\nПредполагая, что цвет пикселя представлен *4-мя* числами (`R` - красный, `G` - зеленый, `B` - синий, `A` - альфа, прозрачность), мы можем использовать следующую формулу для вычисления разницы в цвете (энергии пикселя):\n\n![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)\n\nГде:\n\n- `mEnergy` - *Энергия* (важность) *среднего* пикселя (`[0..626]` если округлить)\n- `lR` - *Красный* цветовой канал *левого* пикселя (`[0..255]`)\n- `mR` - *Красный* цветовой канал *среднего* пикселя (`[0..255]`)\n- `rR` - *Красный* цветовой канал *правого* пикселя (`[0..255]`)\n- `lG` - *Зеленый* цветовой канал *левого* пикселя (`[0..255]`)\n- и так далее...\n\nВ приведенной выше формуле мы пока не используем альфа-канал (прозрачность), предполагая, что изображение не содержит прозрачные пиксели. Позже мы будем использовать альфа-канал для маскировки и удаления объектов.\n\n![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)\n\nПоскольку мы знаем, как найти энергию одного пикселя, мы можем вычислить так называемую **энергетическую карту**, которая будет содержать энергии каждого пикселя изображения. На каждом шаге изменения размера изображения карту энергий необходимо пересчитывать (по крайней мере частично, подробнее об этом ниже), и она будет иметь тот же размер, что и изображение.\n\nНапример, на 1-м шаге у нас будет изображение размером `1000 x 500` и энергетическая карта размером `1000 x 500`. На 2-м шаге изменения размера мы удалим шов с изображения и пересчитаем карту энергий на основе нового уменьшенного изображения. Таким образом, мы получим изображение размером `999 x 500` и карту энергий размером `999 x 500`.\n\nЧем выше энергия пикселя, тем больше вероятность того, что он является частью ребра, важен для содержимого изображения и тем меньше вероятность того, что нам потребуется его удалить.\n\nДля визуализации карты энергий мы можем присвоить более яркий цвет пикселям с большей энергией и более темные цвета пикселям с меньшей энергией. Вот как может выглядеть часть карты энергий. Вы можете увидеть светлую линию, которая представляет край и которую мы хотим сохранить при изменении размера.\n\n![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)\n\nВот реальный пример энергетической карты для изображения, которое вы видели выше (с воздушными шарами).\n\n![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)\n\nВы можете загрузить свое изображение и посмотреть, как будет выглядеть энергетическая карта в [интерактивной версии статьи](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/).\n\nМы можем использовать энергетическую карту, чтобы найти швы (один за другим) с наименьшей энергией и тем самым решить, какие пиксели в конечном итоге должны быть удалены.\n\n![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)\n\nПоиск шва с наименьшими затратами энергии не является тривиальной задачей и требует перебора множества возможных комбинаций пикселей. Мы применим динамическое программирование для оптимизации поиска шва.\n\nВ примере ниже вы можете увидеть карту энергий с первым найденным для нее швом с наименьшей энергией.\n\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)\n\nВ приведенных выше примерах мы уменьшали ширину изображения. Аналогичный подход может быть использован для уменьшения высоты изображения. Для этого нам нужно:\n\n- начать использовать соседей *сверху* и *снизу*, а не *слева* и *справа*, для вычисления энергии пикселя\n- при поиске шва нам нужно двигаться *слева* *направо*, а не *сверху* *вниз*.\n\n## Реализация алгоритма на TypeScript\n\n> Исходный код и функции, упомянутые ниже, можно найти в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver).\n\nДля реализации алгоритма мы будем использовать TypeScript. Если вам нужна версия на JavaScript, вы можете игнорировать (удалить) определения типов и их использование.\n\nДля простоты примеров мы напишем код только для уменьшения *ширины* изображения.\n\n### Уменьшение ширины с учетом содержимого изображения (исходная функция)\n\nДля начала определим некоторые общие типы, которые мы будем использовать при реализации алгоритма.\n\n```typescript\n// Type that describes the image size (width and height).\ntype ImageSize = { w: number, h: number };\n\n// The coordinate of the pixel.\ntype Coordinate = { x: number, y: number };\n\n// The seam is a sequence of pixels (coordinates).\ntype Seam = Coordinate[];\n\n// Energy map is a 2D array that has the same width and height\n// as the image the map is being calculated for.\ntype EnergyMap = number[][];\n\n// Type that describes the image pixel's RGBA color.\ntype Color = [\n  r: number, // Red\n  g: number, // Green\n  b: number, // Blue\n  a: number, // Alpha (transparency)\n] | Uint8ClampedArray;\n```\n\nДля имплементации алгоритма нам необходимо выполнить следующие шаги:\n\n1. Рассчитать **карту энергии** для текущей версии изображения.\n2. Найти **шов** с наименьшей энергией на основе карты энергий (здесь мы применим динамическое программирование).\n3. **Удалить шов** с наименьшей энергией из изображения.\n4. **Повторять** до тех пор, пока ширина изображения не будет уменьшена до нужного значения.\n\n```typescript\ntype ResizeImageWidthArgs = {\n  img: ImageData, // Image data we want to resize.\n  toWidth: number, // Final image width we want the image to shrink to.\n};\n\ntype ResizeImageWidthResult = {\n  img: ImageData, // Resized image data.\n  size: ImageSize, // Resized image size (w x h).\n};\n\n// Performs the content-aware image width resizing using the seam carving method.\nexport const resizeImageWidth = (\n  { img, toWidth }: ResizeImageWidthArgs,\n): ResizeImageWidthResult => {\n  // For performance reasons we want to avoid changing the img data array size.\n  // Instead we'll just keep the record of the resized image width and height separately.\n  const size: ImageSize = { w: img.width, h: img.height };\n\n  // Calculating the number of pixels to remove.\n  const pxToRemove = img.width - toWidth;\n  if (pxToRemove < 0) {\n    throw new Error('Upsizing is not supported for now');\n  }\n\n  let energyMap: EnergyMap | null = null;\n  let seam: Seam | null = null;\n\n  // Removing the lowest energy seams one by one.\n  for (let i = 0; i < pxToRemove; i += 1) {\n    // 1. Calculate the energy map for the current version of the image.\n    energyMap = calculateEnergyMap(img, size);\n\n    // 2. Find the seam with the lowest energy based on the energy map.\n    seam = findLowEnergySeam(energyMap, size);\n\n    // 3. Delete the seam with the lowest energy seam from the image.\n    deleteSeam(img, seam, size);\n\n    // Reduce the image width, and continue iterations.\n    size.w -= 1;\n  }\n\n  // Returning the resized image and its final size.\n  // The img is actually a reference to the ImageData, so technically\n  // the caller of the function already has this pointer. But let's\n  // still return it for better code readability.\n  return { img, size };\n};\n```\n\nИзображение, которому необходимо изменить размер, передается в функцию в формате [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). Вы можете отобразить изображение на canvas-е, а затем извлечь ImageData из того же canvas-а следующим образом:\n\n```javascript\nconst ctx = canvas.getContext('2d');\nconst imgData = ctx.getImageData(0, 0, imgWidth, imgHeight);\n```\n\n> Загрузка и отрисовка изображений в JavaScript выходит за рамки данной статьи, но вы можете найти полный исходный код того, как это можно сделать с помощью React в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver).\n\nТеперь, пошагово реализуем функции `calculateEnergyMap()`, `findLowEnergySeam()` и `deleteSeam()`.\n\n### Расчет энергии пикселя\n\nДля расчета воспользуемся формулой разницы цветов, описанной выше. Для левой и правой краев изображения (когда нет левого или правого соседей) мы игнорируем соседей и не учитываем их при расчете энергии.\n\n```typescript\n// Calculates the energy of a pixel.\nconst getPixelEnergy = (left: Color | null, middle: Color, right: Color | null): number => {\n  // Middle pixel is the pixel we're calculating the energy for.\n  const [mR, mG, mB] = middle;\n\n  // Energy from the left pixel (if it exists).\n  let lEnergy = 0;\n  if (left) {\n    const [lR, lG, lB] = left;\n    lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2;\n  }\n\n  // Energy from the right pixel (if it exists).\n  let rEnergy = 0;\n  if (right) {\n    const [rR, rG, rB] = right;\n    rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2;\n  }\n\n  // Resulting pixel energy.\n  return Math.sqrt(lEnergy + rEnergy);\n};\n```\n\n### Расчет энергетической карты\n\nИзображение, с которым мы работаем, имеет формат [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* матрицей.\n\n```typescript\n// Helper function that returns the color of the pixel.\nconst getPixel = (img: ImageData, { x, y }: Coordinate): Color => {\n  // The ImageData data array is a flat 1D array.\n  // Thus we need to convert x and y coordinates to the linear index.\n  const i = y * img.width + x;\n  const cellsPerColor = 4; // RGBA\n  // For better efficiency, instead of creating a new sub-array we return\n  // a pointer to the part of the ImageData array.\n  return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor);\n};\n\n// Helper function that sets the color of the pixel.\nconst setPixel = (img: ImageData, { x, y }: Coordinate, color: Color): void => {\n  // The ImageData data array is a flat 1D array.\n  // Thus we need to convert x and y coordinates to the linear index.\n  const i = y * img.width + x;\n  const cellsPerColor = 4; // RGBA\n  img.data.set(color, i * cellsPerColor);\n};\n```\n\nДля вычисления карты энергии мы проходим через каждый пиксель изображения и вызываем для него описанную ранее функцию `getPixelEnergy()`.\n\n```typescript\n// Helper function that creates a matrix (2D array) of specific\n// size (w x h) and fills it with specified value.\nconst matrix = <T>(w: number, h: number, filler: T): T[][] => {\n  return new Array(h)\n    .fill(null)\n    .map(() => {\n      return new Array(w).fill(filler);\n    });\n};\n\n// Calculates the energy of each pixel of the image.\nconst calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => {\n  // Create an empty energy map where each pixel has infinitely high energy.\n  // We will update the energy of each pixel.\n  const energyMap: number[][] = matrix<number>(w, h, Infinity);\n  for (let y = 0; y < h; y += 1) {\n    for (let x = 0; x < w; x += 1) {\n      // Left pixel might not exist if we're on the very left edge of the image.\n      const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null;\n      // The color of the middle pixel that we're calculating the energy for.\n      const middle = getPixel(img, { x, y });\n      // Right pixel might not exist if we're on the very right edge of the image.\n      const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null;\n      energyMap[y][x] = getPixelEnergy(left, middle, right);\n    }\n  }\n  return energyMap;\n};\n```\n\n> Карта энергии будет пересчитываться при каждой итерации изменения размера. Это значит, что она будет пересчитываться, скажем, 500 раз, если нам нужно будет уменьшить изображение на 500 пикселей, что выглядит неоптимально. Чтобы ускорить вычисление карты энергии на 2-м, 3-м и последующих этапах, мы можем пересчитать энергию только для тех пикселей, которые расположены вокруг шва, который будет удален. Для простоты эта оптимизация здесь пропущена, но пример с исходным кодом можно найти в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver).\n\n### Нахождение шва с минимальной энергией (применяем динамическое программирование)\n\n> В статье [Dynamic Programming vs Divide-and-Conquer](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) я описывал некоторые аспекты динамического программирования на примере нахождения \"расстояния Левенштейна\" (преобразование одной строки в другую). Возможно она будет полезна для ознакомления.\n\nПроблема, которую нам необходимо решить заключается в нахождении пути (шва) на энергетической карте, который идет от верхней границы изображения к нижней и имеет минимальную энергию (сумма энергий пикселей, составляющих шов должна быть минимальной).\n\n#### \"Наивный\" подход (naive)\n\nПрямолинейный (\"наивный\") подход — перебрать все возможные пути один за другим.\n\n![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)\n\nДвигаясь сверху вниз, для каждого пикселя у нас есть 3 варианта (↙︎ идти вниз-влево, ↓ вниз, ↘︎ идти вниз-вправо). Это дает нам временную сложность `O (w * 3 ^ h)` или просто `O (3 ^ h)`, где `w` и` h` - ширина и высота изображения. Такой подход выглядит неоптимальным.\n\n#### \"Жадный\" подход (greedy)\n\nЖадный подход — выбирать следующий пиксель как пиксель с наименьшей энергией, надеясь, что результирующая энергия шва будет наименьшей.\n\n![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)\n\nЖадный подход приведет нас к не самому худшему решению, но он не сможет гарантировать, что мы найдем наилучшее доступное решение. На картинке выше видно, как мы выбрали `5` вместо `10` и пропустили цепочку оптимальных пикселей.\n\nПлюс этого подхода в том, что он быстрый и имеет временную сложность `O(w + h)`, где `w` и `h` - это ширина и высота изображения. В этом случае плата за скорость — низкое качество ресайза (много искажений). Временная сложность обусловлена тем, что нужно найти минимальное значение в первом ряду (обход `w` ячеек), а затем исследовать только 3 соседних пикселя для каждого ряда (обход `h` рядов).\n\n#### Используем динамическое программирование\n\nВы, наверное, заметили, что в наивном подходе мы снова и снова суммировали одни и те же энергии пикселей, вычисляя энергию образовавшихся швов.\n\n![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)\n\nВ примере выше видно, что для первых двух швов мы повторно используем энергию более короткого шва (который имеет энергию `235`). Вместо одной операции `235 + 70` для вычисления энергии 2-го шва мы делаем четыре операции `(5 + 0 + 80 + 150) + 70`.\n\n> Тот факт, что мы повторно используем энергию предыдущего шва для вычисления энергии текущего шва, может быть применен рекурсивно ко всем более коротким швам до самого верхнего 1-го ряда. Когда у нас есть такие перекрывающиеся под-проблемы, [это признак](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/), что общая задача *может* быть оптимизирована с использованием динамического программирования.\n\nТаким образом, мы можем **сохранить энергию текущего шва** для конкретного пикселя в дополнительной таблице `samsEnergies`, чтобы повторно использовать ее при расчете энергии следующих швов (таблица `samsEnergies` будет иметь тот же размер, что и энергетическая карта и само изображение).\n\nОбратите также внимание, что для большинства пикселей в изображении (например, для левого нижнего) мы можем иметь *несколько* значений энергий предыдущих швов.\n\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)\n\nТак как мы ищем шов с наименьшей результирующей энергией, имеет смысл выбирать и предыдущий шов с наименьшей результирующей энергией.\n\n![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)\n\nКак правило, у нас есть три возможных предыдущих шва, которые текущий пиксель продолжает:\n\n![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\nМожем посмотреть на это с такой стороны:\n\n- Ячейка `[1][x]`: содержит наименьшую возможную энергию шва, который начинается где-то в ряду `[0][?] ` и заканчивается в ячейке `[1][x]`.\n- **Текущая ячейка** `[2][3]`: содержит наименьшую возможную энергию шва, который начинается где-то в ряду `[0][?] ` и заканчивается в ячейке `[2][3]`. Для вычисления нужно суммировать энергию текущего пикселя `[2][3]` (из энергетической карты) с `min(seam_energy_1_2, seam_energy_1_3, seam_energy_1_4)`.\n\nЕсли мы заполним таблицу `ShesamsEnergies` полностью, то минимальное число в нижнем ряду будет наименьшей возможной энергией шва.\n\nПопробуем заполнить несколько ячеек этой таблицы, чтобы посмотреть, как это работает.\n\n![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)\n\nПосле заполнения таблицы `ShesamsEnergies` видно, что в нижнем ряду пиксель с самой низкой энергией имеет значение `50`. Для удобства во время генерации `samsEnergies` для каждого пикселя мы можем сохранить не только энергию шва, но и координаты предыдущего шва с наименьшей энергией. Это даст нам возможность легко восстанавливать траекторию шва снизу вверх.\n\nВременная сложность DP подхода составит `O(w * h)`, где `w` и `h` - это ширина и высота изображения. Обусловлена она тем, что нужно вычислить энергии для *всех* пикселей изображения.\n\nВот пример того, как эта логика может быть реализована:\n\n```typescript\n// The metadata for the pixels in the seam.\ntype SeamPixelMeta = {\n  energy: number, // The energy of the pixel.\n  coordinate: Coordinate, // The coordinate of the pixel.\n  previous: Coordinate | null, // The previous pixel in a seam.\n};\n\n// Finds the seam (the sequence of pixels from top to bottom) that has the\n// lowest resulting energy using the Dynamic Programming approach.\nconst findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {\n  // The 2D array of the size of w and h, where each pixel contains the\n  // seam metadata (pixel energy, pixel coordinate and previous pixel from\n  // the lowest energy seam at this point).\n  const seamsEnergies: (SeamPixelMeta | null)[][] = matrix<SeamPixelMeta | null>(w, h, null);\n\n  // Populate the first row of the map by just copying the energies\n  // from the energy map.\n  for (let x = 0; x < w; x += 1) {\n    const y = 0;\n    seamsEnergies[y][x] = {\n      energy: energyMap[y][x],\n      coordinate: { x, y },\n      previous: null,\n    };\n  }\n\n  // Populate the rest of the rows.\n  for (let y = 1; y < h; y += 1) {\n    for (let x = 0; x < w; x += 1) {\n      // Find the top adjacent cell with minimum energy.\n      // This cell would be the tail of a seam with lowest energy at this point.\n      // It doesn't mean that this seam (path) has lowest energy globally.\n      // Instead, it means that we found a path with the lowest energy that may lead\n      // us to the current pixel with the coordinates x and y.\n      let minPrevEnergy = Infinity;\n      let minPrevX: number = x;\n      for (let i = (x - 1); i <= (x + 1); i += 1) {\n        if (i >= 0 && i < w && seamsEnergies[y - 1][i].energy < minPrevEnergy) {\n          minPrevEnergy = seamsEnergies[y - 1][i].energy;\n          minPrevX = i;\n        }\n      }\n\n      // Update the current cell.\n      seamsEnergies[y][x] = {\n        energy: minPrevEnergy + energyMap[y][x],\n        coordinate: { x, y },\n        previous: { x: minPrevX, y: y - 1 },\n      };\n    }\n  }\n\n  // Find where the minimum energy seam ends.\n  // We need to find the tail of the lowest energy seam to start\n  // traversing it from its tail to its head (from the bottom to the top).\n  let lastMinCoordinate: Coordinate | null = null;\n  let minSeamEnergy = Infinity;\n  for (let x = 0; x < w; x += 1) {\n    const y = h - 1;\n    if (seamsEnergies[y][x].energy < minSeamEnergy) {\n      minSeamEnergy = seamsEnergies[y][x].energy;\n      lastMinCoordinate = { x, y };\n    }\n  }\n\n  // Find the lowest energy energy seam.\n  // Once we know where the tail is we may traverse and assemble the lowest\n  // energy seam based on the \"previous\" value of the seam pixel metadata.\n  const seam: Seam = [];\n  if (!lastMinCoordinate) {\n    return seam;\n  }\n\n  const { x: lastMinX, y: lastMinY } = lastMinCoordinate;\n\n  // Adding new pixel to the seam path one by one until we reach the top.\n  let currentSeam = seamsEnergies[lastMinY][lastMinX];\n  while (currentSeam) {\n    seam.push(currentSeam.coordinate);\n    const prevMinCoordinates = currentSeam.previous;\n    if (!prevMinCoordinates) {\n      currentSeam = null;\n    } else {\n      const { x: prevMinX, y: prevMinY } = prevMinCoordinates;\n      currentSeam = seamsEnergies[prevMinY][prevMinX];\n    }\n  }\n\n  return seam;\n};\n```\n\n### Удаление шва с минимальной энергией\n\nКак только мы нашли шов с наименьшей суммарной энергией, нам нужно удалить (вырезать) пиксели, которые образуют его из изображения. Удаление происходит путем смещения пикселей справа от шва на `1px` влево. Из соображений производительности мы не будем удалять крайний столбик пикселей. Вместо этого, компонент, отвечающий за отрисовку уменьшенного изображения просто проигнорирует ту часть изображения, которая лежит за пределами обрезанной ширины.\n\n![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)\n\n```typescript\n// Deletes the seam from the image data.\n// We delete the pixel in each row and then shift the rest of the row pixels to the left.\nconst deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => {\n  seam.forEach(({ x: seamX, y: seamY }: Coordinate) => {\n    for (let x = seamX; x < (w - 1); x += 1) {\n      const nextPixel = getPixel(img, { x: x + 1, y: seamY });\n      setPixel(img, { x, y: seamY }, nextPixel);\n    }\n  });\n};\n```\n\n## Удаление объектов с изображения\n\nSeam Carving алгоритм пытается сначала удалить швы, состоящие из низкоэнергетических пикселей. Мы могли бы использовать этот факт и, присвоив низкую энергию некоторым пикселям вручную (например, нарисовав на изображении маску), мы могли бы заставить алгоритм удалить отмеченные пиксели (*объекты*).\n\nВ настоящее время в функции `getPixelEnergy()` мы используем только каналы цветов `R`, `G`, `B` для вычисления энергии пикселей. Но есть еще и параметр `A` (альфа, прозрачность), который мы не использовали. Мы можем использовать канал прозрачности, чтобы \"сказать\" алгоритму, что прозрачные пиксели — это те пиксели, которые мы хотим удалить. Вы можете ознакомиться с [исходным кодом функции getPixelEnergy()](https://github.com/trekhleb/js-image-carver/blob/main/src/utils/contentAwareResizer.ts#L54), которая учитывает прозрачность.\n\nВот как при этом будет выглядеть удаление объектов:\n\n![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)\n\n## Проблемы алгоритма и дальнейшие планы\n\nПриложение [JS IMAGE CARVER](https://github.com/trekhleb/js-image-carver) далеко от идеала и не является приложением production-ready качества. Основной его целью была возможность интерактивного экспериментирования с алгоритмом. Поэтому в дальнейших планах — использовать его именно для экспериментов.\n\nВ [оригинальной статье](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) описывается, как алгоритм может быть использован не только для уменьшения, но и для **увеличения изображения**. Увеличение (расширение) изображения, в свою очередь, может быть использовано для **автоматического расширения изображения до его исходной ширины после удаления объектов**.\n\nЕще одной интересной областью экспериментов может быть попытка ускорить алгоритм, чтобы он работал в режиме **реального времени**.\n\n> Таковы планы на будущее, но пока, надеюсь, пример с уменьшением изображения был интересен и полезен для вас. Также надеюсь, что вам было интересно увидеть применение динамического программирования в задачах, приближенных к реальности.\n>\n> Удачи с вашими собственными экспериментами!\n"
  },
  {
    "path": "src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js",
    "content": "import fs from 'fs';\nimport { PNG } from 'pngjs';\n\nimport resizeImageWidth from '../resizeImageWidth';\n\nconst testImageBeforePath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-before.png';\nconst testImageAfterPath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-after.png';\n\n/**\n * Compares two images and finds the number of different pixels.\n *\n * @param {ImageData} imgA - ImageData for the first image.\n * @param {ImageData} imgB - ImageData for the second image.\n * @param {number} threshold - Color difference threshold [0..255]. Smaller - stricter.\n * @returns {number} - Number of different pixels.\n */\nfunction pixelsDiff(imgA, imgB, threshold = 0) {\n  if (imgA.width !== imgB.width || imgA.height !== imgB.height) {\n    throw new Error('Images must have the same size');\n  }\n\n  let differentPixels = 0;\n  const numColorParams = 4; // RGBA\n\n  for (let pixelIndex = 0; pixelIndex < imgA.data.length; pixelIndex += numColorParams) {\n    // Get pixel's color for each image.\n    const [aR, aG, aB] = imgA.data.subarray(pixelIndex, pixelIndex + numColorParams);\n    const [bR, bG, bB] = imgB.data.subarray(pixelIndex, pixelIndex + numColorParams);\n\n    // Get average pixel's color for each image (make them greyscale).\n    const aAvgColor = Math.floor((aR + aG + aB) / 3);\n    const bAvgColor = Math.floor((bR + bG + bB) / 3);\n\n    // Compare pixel colors.\n    if (Math.abs(aAvgColor - bAvgColor) > threshold) {\n      differentPixels += 1;\n    }\n  }\n\n  return differentPixels;\n}\n\nconst pngLoad = (path) => new Promise((resolve) => {\n  fs.createReadStream(path)\n    .pipe(new PNG())\n    .on('parsed', function Parsed() {\n      /** @type {ImageData} */\n      const imageData = {\n        colorSpace: 'srgb',\n        width: this.width,\n        height: this.height,\n        data: this.data,\n      };\n      resolve(imageData);\n    });\n});\n\ndescribe('resizeImageWidth', () => {\n  it('should perform content-aware image width reduction', async () => {\n    const imgBefore = await pngLoad(testImageBeforePath);\n    const imgAfter = await pngLoad(testImageAfterPath);\n\n    const toWidth = Math.floor(imgBefore.width / 2);\n\n    const {\n      img: imgResized,\n      size: resizedSize,\n    } = resizeImageWidth({ img: imgBefore, toWidth });\n\n    expect(imgResized).toBeDefined();\n    expect(resizedSize).toBeDefined();\n\n    expect(resizedSize).toEqual({ w: toWidth, h: imgBefore.height });\n    expect(imgResized.width).toBe(imgAfter.width);\n    expect(imgResized.height).toBe(imgAfter.height);\n\n    const colorThreshold = 50;\n    const differentPixels = pixelsDiff(imgResized, imgAfter, colorThreshold);\n\n    // Allow 10% of pixels to be different\n    const pixelsThreshold = Math.floor((imgAfter.width * imgAfter.height) / 10);\n\n    expect(differentPixels).toBeLessThanOrEqual(pixelsThreshold);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/image-processing/seam-carving/resizeImageWidth.js",
    "content": "import { getPixel, setPixel } from '../utils/imageData';\n\n/**\n * The seam is a sequence of pixels (coordinates).\n * @typedef {PixelCoordinate[]} Seam\n */\n\n/**\n * Energy map is a 2D array that has the same width and height\n * as the image the map is being calculated for.\n * @typedef {number[][]} EnergyMap\n */\n\n/**\n * The metadata for the pixels in the seam.\n * @typedef {Object} SeamPixelMeta\n * @property {number} energy - the energy of the pixel.\n * @property {PixelCoordinate} coordinate - the coordinate of the pixel.\n * @property {?PixelCoordinate} previous - the previous pixel in a seam.\n */\n\n/**\n * Type that describes the image size (width and height)\n * @typedef {Object} ImageSize\n * @property {number} w - image width.\n * @property {number} h - image height.\n */\n\n/**\n * @typedef {Object} ResizeImageWidthArgs\n * @property {ImageData} img - image data we want to resize.\n * @property {number} toWidth - final image width we want the image to shrink to.\n */\n\n/**\n * @typedef {Object} ResizeImageWidthResult\n * @property {ImageData} img - resized image data.\n * @property {ImageSize} size - resized image size.\n */\n\n/**\n * Helper function that creates a matrix (2D array) of specific\n * size (w x h) and fills it with specified value.\n * @param {number} w\n * @param {number} h\n * @param {?(number | SeamPixelMeta)} filler\n * @returns {?(number | SeamPixelMeta)[][]}\n */\nconst matrix = (w, h, filler) => {\n  return new Array(h)\n    .fill(null)\n    .map(() => {\n      return new Array(w).fill(filler);\n    });\n};\n\n/**\n * Calculates the energy of a pixel.\n * @param {?PixelColor} left\n * @param {PixelColor} middle\n * @param {?PixelColor} right\n * @returns {number}\n */\nconst getPixelEnergy = (left, middle, right) => {\n  // Middle pixel is the pixel we're calculating the energy for.\n  const [mR, mG, mB] = middle;\n\n  // Energy from the left pixel (if it exists).\n  let lEnergy = 0;\n  if (left) {\n    const [lR, lG, lB] = left;\n    lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2;\n  }\n\n  // Energy from the right pixel (if it exists).\n  let rEnergy = 0;\n  if (right) {\n    const [rR, rG, rB] = right;\n    rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2;\n  }\n\n  // Resulting pixel energy.\n  return Math.sqrt(lEnergy + rEnergy);\n};\n\n/**\n * Calculates the energy of each pixel of the image.\n * @param {ImageData} img\n * @param {ImageSize} size\n * @returns {EnergyMap}\n */\nconst calculateEnergyMap = (img, { w, h }) => {\n  // Create an empty energy map where each pixel has infinitely high energy.\n  // We will update the energy of each pixel.\n  const energyMap = matrix(w, h, Infinity);\n  for (let y = 0; y < h; y += 1) {\n    for (let x = 0; x < w; x += 1) {\n      // Left pixel might not exist if we're on the very left edge of the image.\n      const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null;\n      // The color of the middle pixel that we're calculating the energy for.\n      const middle = getPixel(img, { x, y });\n      // Right pixel might not exist if we're on the very right edge of the image.\n      const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null;\n      energyMap[y][x] = getPixelEnergy(left, middle, right);\n    }\n  }\n  return energyMap;\n};\n\n/**\n * Finds the seam (the sequence of pixels from top to bottom) that has the\n * lowest resulting energy using the Dynamic Programming approach.\n * @param {EnergyMap} energyMap\n * @param {ImageSize} size\n * @returns {Seam}\n */\nconst findLowEnergySeam = (energyMap, { w, h }) => {\n  // The 2D array of the size of w and h, where each pixel contains the\n  // seam metadata (pixel energy, pixel coordinate and previous pixel from\n  // the lowest energy seam at this point).\n  const seamPixelsMap = matrix(w, h, null);\n\n  // Populate the first row of the map by just copying the energies\n  // from the energy map.\n  for (let x = 0; x < w; x += 1) {\n    const y = 0;\n    seamPixelsMap[y][x] = {\n      energy: energyMap[y][x],\n      coordinate: { x, y },\n      previous: null,\n    };\n  }\n\n  // Populate the rest of the rows.\n  for (let y = 1; y < h; y += 1) {\n    for (let x = 0; x < w; x += 1) {\n      // Find the top adjacent cell with minimum energy.\n      // This cell would be the tail of a seam with lowest energy at this point.\n      // It doesn't mean that this seam (path) has lowest energy globally.\n      // Instead, it means that we found a path with the lowest energy that may lead\n      // us to the current pixel with the coordinates x and y.\n      let minPrevEnergy = Infinity;\n      let minPrevX = x;\n      for (let i = (x - 1); i <= (x + 1); i += 1) {\n        if (i >= 0 && i < w && seamPixelsMap[y - 1][i].energy < minPrevEnergy) {\n          minPrevEnergy = seamPixelsMap[y - 1][i].energy;\n          minPrevX = i;\n        }\n      }\n\n      // Update the current cell.\n      seamPixelsMap[y][x] = {\n        energy: minPrevEnergy + energyMap[y][x],\n        coordinate: { x, y },\n        previous: { x: minPrevX, y: y - 1 },\n      };\n    }\n  }\n\n  // Find where the minimum energy seam ends.\n  // We need to find the tail of the lowest energy seam to start\n  // traversing it from its tail to its head (from the bottom to the top).\n  let lastMinCoordinate = null;\n  let minSeamEnergy = Infinity;\n  for (let x = 0; x < w; x += 1) {\n    const y = h - 1;\n    if (seamPixelsMap[y][x].energy < minSeamEnergy) {\n      minSeamEnergy = seamPixelsMap[y][x].energy;\n      lastMinCoordinate = { x, y };\n    }\n  }\n\n  // Find the lowest energy energy seam.\n  // Once we know where the tail is we may traverse and assemble the lowest\n  // energy seam based on the \"previous\" value of the seam pixel metadata.\n  const seam = [];\n\n  const { x: lastMinX, y: lastMinY } = lastMinCoordinate;\n\n  // Adding new pixel to the seam path one by one until we reach the top.\n  let currentSeam = seamPixelsMap[lastMinY][lastMinX];\n  while (currentSeam) {\n    seam.push(currentSeam.coordinate);\n    const prevMinCoordinates = currentSeam.previous;\n    if (!prevMinCoordinates) {\n      currentSeam = null;\n    } else {\n      const { x: prevMinX, y: prevMinY } = prevMinCoordinates;\n      currentSeam = seamPixelsMap[prevMinY][prevMinX];\n    }\n  }\n\n  return seam;\n};\n\n/**\n * Deletes the seam from the image data.\n * We delete the pixel in each row and then shift the rest of the row pixels to the left.\n * @param {ImageData} img\n * @param {Seam} seam\n * @param {ImageSize} size\n */\nconst deleteSeam = (img, seam, { w }) => {\n  seam.forEach(({ x: seamX, y: seamY }) => {\n    for (let x = seamX; x < (w - 1); x += 1) {\n      const nextPixel = getPixel(img, { x: x + 1, y: seamY });\n      setPixel(img, { x, y: seamY }, nextPixel);\n    }\n  });\n};\n\n/**\n * Performs the content-aware image width resizing using the seam carving method.\n * @param {ResizeImageWidthArgs} args\n * @returns {ResizeImageWidthResult}\n */\nconst resizeImageWidth = ({ img, toWidth }) => {\n  /**\n   * For performance reasons we want to avoid changing the img data array size.\n   * Instead we'll just keep the record of the resized image width and height separately.\n   * @type {ImageSize}\n   */\n  const size = { w: img.width, h: img.height };\n\n  // Calculating the number of pixels to remove.\n  const pxToRemove = img.width - toWidth;\n\n  let energyMap = null;\n  let seam = null;\n\n  // Removing the lowest energy seams one by one.\n  for (let i = 0; i < pxToRemove; i += 1) {\n    // 1. Calculate the energy map for the current version of the image.\n    energyMap = calculateEnergyMap(img, size);\n\n    // 2. Find the seam with the lowest energy based on the energy map.\n    seam = findLowEnergySeam(energyMap, size);\n\n    // 3. Delete the seam with the lowest energy seam from the image.\n    deleteSeam(img, seam, size);\n\n    // Reduce the image width, and continue iterations.\n    size.w -= 1;\n  }\n\n  // Returning the resized image and its final size.\n  // The img is actually a reference to the ImageData, so technically\n  // the caller of the function already has this pointer. But let's\n  // still return it for better code readability.\n  return { img, size };\n};\n\nexport default resizeImageWidth;\n"
  },
  {
    "path": "src/algorithms/image-processing/utils/imageData.js",
    "content": "/**\n * @typedef {ArrayLike<number> | Uint8ClampedArray} PixelColor\n */\n\n/**\n * @typedef {Object} PixelCoordinate\n * @property {number} x - horizontal coordinate.\n * @property {number} y - vertical coordinate.\n */\n\n/**\n * Helper function that returns the color of the pixel.\n * @param {ImageData} img\n * @param {PixelCoordinate} coordinate\n * @returns {PixelColor}\n */\nexport const getPixel = (img, { x, y }) => {\n  // The ImageData data array is a flat 1D array.\n  // Thus we need to convert x and y coordinates to the linear index.\n  const i = y * img.width + x;\n  const cellsPerColor = 4; // RGBA\n  // For better efficiency, instead of creating a new sub-array we return\n  // a pointer to the part of the ImageData array.\n  return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor);\n};\n\n/**\n * Helper function that sets the color of the pixel.\n * @param {ImageData} img\n * @param {PixelCoordinate} coordinate\n * @param {PixelColor} color\n */\nexport const setPixel = (img, { x, y }, color) => {\n  // The ImageData data array is a flat 1D array.\n  // Thus we need to convert x and y coordinates to the linear index.\n  const i = y * img.width + x;\n  const cellsPerColor = 4; // RGBA\n  img.data.set(color, i * cellsPerColor);\n};\n"
  },
  {
    "path": "src/algorithms/linked-list/reverse-traversal/README.md",
    "content": "# Reversed Linked List Traversal\n\n_Read this in other languages:_\n[_中文_](README.zh-CN.md),\n[_Português_](README.pt-BR.md)\n\nThe task is to traverse the given linked list in reversed order.\n\nFor example for the following linked list: \n\n![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)\n\nThe order of traversal should be:\n\n```text\n37 → 99 → 12\n```\n\nThe time complexity is `O(n)` because we visit every node only once.\n\n## Reference\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n"
  },
  {
    "path": "src/algorithms/linked-list/reverse-traversal/README.pt-BR.md",
    "content": "# Travessia de Lista Encadeada Reversa\n\n_Leia isso em outros idiomas:_\n[_中文_](README.zh-CN.md),\n[_English_](README.md)\n\nA tarefa é percorrer a lista encadeada fornecida em ordem inversa.\n\nPor exemplo, para a seguinte lista vinculada:\n\n![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)\n\nA ordem de travessia deve ser:\n\n```texto\n37 → 99 → 12\n```\n\nA complexidade de tempo é `O(n)` porque visitamos cada nó apenas uma vez.\n\n## Referência\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n"
  },
  {
    "path": "src/algorithms/linked-list/reverse-traversal/README.zh-CN.md",
    "content": "# 链表倒序遍历\n\n我们的任务是倒序遍历给定的链表\n\n比如下面的链表\n\n![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)\n\n遍历的顺序应该是\n\n```text\n37 → 99 → 12\n```\n\n因为我们每个节点只访问一次，时间复杂度应该是`O(n)`\n\n## 参考\n\n- [Wikipedia](https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8)\n"
  },
  {
    "path": "src/algorithms/linked-list/reverse-traversal/__test__/reverseTraversal.test.js",
    "content": "import LinkedList from '../../../../data-structures/linked-list/LinkedList';\nimport reverseTraversal from '../reverseTraversal';\n\ndescribe('reverseTraversal', () => {\n  it('should traverse linked list in reverse order', () => {\n    const linkedList = new LinkedList();\n\n    linkedList\n      .append(1)\n      .append(2)\n      .append(3);\n\n    const traversedNodeValues = [];\n    const traversalCallback = (nodeValue) => {\n      traversedNodeValues.push(nodeValue);\n    };\n\n    reverseTraversal(linkedList, traversalCallback);\n\n    expect(traversedNodeValues).toEqual([3, 2, 1]);\n  });\n});\n\n// it('should reverse traversal the linked list with callback', () => {\n//   const linkedList = new LinkedList();\n//\n//   linkedList\n//     .append(1)\n//     .append(2)\n//     .append(3);\n//\n//   expect(linkedList.toString()).toBe('1,2,3');\n//   expect(linkedList.reverseTraversal(linkedList.head, value => value * 2)).toEqual([6, 4, 2]);\n//   expect(() => linkedList.reverseTraversal(linkedList.head)).toThrow();\n// });\n"
  },
  {
    "path": "src/algorithms/linked-list/reverse-traversal/reverseTraversal.js",
    "content": "/**\n * Traversal callback function.\n * @callback traversalCallback\n * @param {*} nodeValue\n */\n\n/**\n * @param {LinkedListNode} node\n * @param {traversalCallback} callback\n */\nfunction reverseTraversalRecursive(node, callback) {\n  if (node) {\n    reverseTraversalRecursive(node.next, callback);\n    callback(node.value);\n  }\n}\n\n/**\n * @param {LinkedList} linkedList\n * @param {traversalCallback} callback\n */\nexport default function reverseTraversal(linkedList, callback) {\n  reverseTraversalRecursive(linkedList.head, callback);\n}\n"
  },
  {
    "path": "src/algorithms/linked-list/traversal/README.md",
    "content": "# Linked List Traversal\n\n_Read this in other languages:_\n[_Русский_](README.ru-RU.md),\n[_中文_](README.zh-CN.md),\n[_Português_](README.pt-BR.md)\n\nThe task is to traverse the given linked list in straight order.\n\nFor example for the following linked list:\n\n![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)\n\nThe order of traversal should be:\n\n```text\n12 → 99 → 37\n```\n\nThe time complexity is `O(n)` because we visit every node only once.\n\n## Reference\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n"
  },
  {
    "path": "src/algorithms/linked-list/traversal/README.pt-BR.md",
    "content": "# Travessia de Lista Encadeada\n\n_Leia isso em outros idiomas:_\n[_Русский_](README.ru-RU.md),\n[_中文_](README.zh-CN.md),\n[_English_](README.md)\n\nA tarefa é percorrer a lista encadeada fornecida em ordem direta.\n\nPor exemplo, para a seguinte lista vinculada:\n\n![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)\n\nA ordem de travessia deve ser:\n\n```texto\n12 → 99 → 37\n```\n\nA complexidade de tempo é `O(n)` porque visitamos cada nó apenas uma vez.\n\n## Referência\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n"
  },
  {
    "path": "src/algorithms/linked-list/traversal/README.ru-RU.md",
    "content": "# Обход связного списка\n\nЗадача состоит в том, чтобы обойти связный список в прямом порядке.\n\nНапример, для следующего связного списка:\n\n![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)\n\nПорядок обхода будет такой:\n\n```text\n12 → 99 → 37\n```\n\nВременная сложность - `O(n)`, потому что мы посещаем каждый узел только один раз.\n\n## Ссылки\n\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)\n"
  },
  {
    "path": "src/algorithms/linked-list/traversal/README.zh-CN.md",
    "content": "# 链表遍历\n\n我们的任务是顺序遍历给定的链表\n\n比如下面的链表\n\n![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)\n\n遍历的顺序应该是\n\n```text\n12 → 99 → 37\n```\n\n因为我们每个节点只访问一次，时间复杂度应该是`O(n)`\n\n## 参考\n\n- [Wikipedia](https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8)"
  },
  {
    "path": "src/algorithms/linked-list/traversal/__test__/traversal.test.js",
    "content": "import LinkedList from '../../../../data-structures/linked-list/LinkedList';\nimport traversal from '../traversal';\n\ndescribe('traversal', () => {\n  it('should traverse linked list', () => {\n    const linkedList = new LinkedList();\n\n    linkedList\n      .append(1)\n      .append(2)\n      .append(3);\n\n    const traversedNodeValues = [];\n    const traversalCallback = (nodeValue) => {\n      traversedNodeValues.push(nodeValue);\n    };\n\n    traversal(linkedList, traversalCallback);\n\n    expect(traversedNodeValues).toEqual([1, 2, 3]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/linked-list/traversal/traversal.js",
    "content": "/**\n * Traversal callback function.\n * @callback traversalCallback\n * @param {*} nodeValue\n */\n\n/**\n * @param {LinkedList} linkedList\n * @param {traversalCallback} callback\n */\nexport default function traversal(linkedList, callback) {\n  let currentNode = linkedList.head;\n\n  while (currentNode) {\n    callback(currentNode.value);\n    currentNode = currentNode.next;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/math/binary-floating-point/README.md",
    "content": "# Binary representation of floating-point numbers\n\nHave 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)?\n\nIt 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]`:\n\n```text\n(0000000000000000)₂ = (0)₁₀\n\n(0000000000010001)₂ =\n    (1 × 2⁴) +\n    (0 × 2³) +\n    (0 × 2²) +\n    (0 × 2¹) +\n    (1 × 2⁰) = (17)₁₀\n\n(1111111111111111)₂ =\n    (1 × 2¹⁵) +\n    (1 × 2¹⁴) +\n    (1 × 2¹³) +\n    (1 × 2¹²) +\n    (1 × 2¹¹) +\n    (1 × 2¹⁰) +\n    (1 × 2⁹) +\n    (1 × 2⁸) +\n    (1 × 2⁷) +\n    (1 × 2⁶) +\n    (1 × 2⁵) +\n    (1 × 2⁴) +\n    (1 × 2³) +\n    (1 × 2²) +\n    (1 × 2¹) +\n    (1 × 2⁰) = (65535)₁₀\n```\n\nIf 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\nAs 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).\n\nWe'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.\n\nThe 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).\n\nTo 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.\n\n![Scientific number notation](images/03-scientific-notation.png)\n\nAs you may see from the image, the number representation might be split into three parts:\n\n- **sign**\n- **fraction (aka significand)** - the valuable digits (the meaning, the payload) of the number\n- **exponent** - controls how far and in which direction to move the decimal point in the fraction\n\nThe **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.\n\nInstead 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:\n\n| Floating-point format | Total bits | Sign bits | Exponent bits | Fraction bits | Base |\n| :-------------------- | :--------: | :-------: | :-----------: | :--------------: | :--: |\n| [Half-precision](https://en.wikipedia.org/wiki/Half-precision_floating-point_format)        | 16         | 1         | 5             | 10               | 2    |\n| [Single-precision](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)      | 32         | 1         | 8             | 23               | 2    |\n| [Double-precision](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)      | 64         | 1         | 11            | 52               | 2    |\n\nWith 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).\n\n> 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³⁸.\n\nTo 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:\n\n```\nexponent_bias = 2 ^ (k−1) − 1\n\nk - number of exponent bits\n```\n\nI'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.\n\n![Half-precision floating point number format explained in one picture](images/02-half-precision-floating-point-number-explained.png)\n\n> 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\n\nHere is the number ranges that different floating-point formats support:\n\n| Floating-point format | Exp min | Exp max | Range            | Min positive |\n| :-------------------- | :------ | :------ | :--------------- | :----------- |\n| Half-precision        | −14     | +15     | ±65,504          | 6.10 × 10⁻⁵  |\n| Single-precision      | −126    | +127    | ±3.4028235 × 10³⁸| 1.18 × 10⁻³⁸ |\n\nBe 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)\n\n## Code examples\n\n- 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)\n- See the [floatAsBinaryString.js](floatAsBinaryString.js) for the example of how to see the actual binary representation of the floating-point number in JavaScript\n\n## References\n\nYou might also want to check out the following resources to get a deeper understanding of the binary representation of floating-point numbers:\n\n- [Interactive version of this article](https://trekhleb.dev/blog/2021/binary-floating-point/) (allows setting the bits manually and seeing the resulting floating number)\n- [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)\n- [Float Exposed](https://float.exposed/)\n- [IEEE754 Visualization](https://bartaz.github.io/ieee754-visualization/)\n"
  },
  {
    "path": "src/algorithms/math/binary-floating-point/__tests__/bitsToFloat.test.js",
    "content": "import { testCases16Bits, testCases32Bits, testCases64Bits } from '../testCases';\nimport { bitsToFloat16, bitsToFloat32, bitsToFloat64 } from '../bitsToFloat';\n\ndescribe('bitsToFloat16', () => {\n  it('should convert floating point binary bits to floating point decimal number', () => {\n    for (let testCaseIndex = 0; testCaseIndex < testCases16Bits.length; testCaseIndex += 1) {\n      const [decimal, binary] = testCases16Bits[testCaseIndex];\n      const bits = binary.split('').map((bitString) => parseInt(bitString, 10));\n      expect(bitsToFloat16(bits)).toBeCloseTo(decimal, 4);\n    }\n  });\n});\n\ndescribe('bitsToFloat32', () => {\n  it('should convert floating point binary bits to floating point decimal number', () => {\n    for (let testCaseIndex = 0; testCaseIndex < testCases32Bits.length; testCaseIndex += 1) {\n      const [decimal, binary] = testCases32Bits[testCaseIndex];\n      const bits = binary.split('').map((bitString) => parseInt(bitString, 10));\n      expect(bitsToFloat32(bits)).toBeCloseTo(decimal, 7);\n    }\n  });\n});\n\ndescribe('bitsToFloat64', () => {\n  it('should convert floating point binary bits to floating point decimal number', () => {\n    for (let testCaseIndex = 0; testCaseIndex < testCases64Bits.length; testCaseIndex += 1) {\n      const [decimal, binary] = testCases64Bits[testCaseIndex];\n      const bits = binary.split('').map((bitString) => parseInt(bitString, 10));\n      expect(bitsToFloat64(bits)).toBeCloseTo(decimal, 14);\n    }\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/binary-floating-point/__tests__/floatAsBinaryString.test.js",
    "content": "import { floatAs32BinaryString, floatAs64BinaryString } from '../floatAsBinaryString';\nimport { testCases32Bits, testCases64Bits } from '../testCases';\n\ndescribe('floatAs32Binary', () => {\n  it('should create a binary representation of the floating numbers', () => {\n    for (let testCaseIndex = 0; testCaseIndex < testCases32Bits.length; testCaseIndex += 1) {\n      const [decimal, binary] = testCases32Bits[testCaseIndex];\n      expect(floatAs32BinaryString(decimal)).toBe(binary);\n    }\n  });\n});\n\ndescribe('floatAs64Binary', () => {\n  it('should create a binary representation of the floating numbers', () => {\n    for (let testCaseIndex = 0; testCaseIndex < testCases64Bits.length; testCaseIndex += 1) {\n      const [decimal, binary] = testCases64Bits[testCaseIndex];\n      expect(floatAs64BinaryString(decimal)).toBe(binary);\n    }\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/binary-floating-point/bitsToFloat.js",
    "content": "/**\n * Sequence of 0s and 1s.\n * @typedef {number[]} Bits\n */\n\n/**\n * @typedef {{\n *   signBitsCount: number,\n *   exponentBitsCount: number,\n *   fractionBitsCount: number,\n * }} PrecisionConfig\n */\n\n/**\n * @typedef {{\n *   half: PrecisionConfig,\n *   single: PrecisionConfig,\n *   double: PrecisionConfig\n * }} PrecisionConfigs\n */\n\n/**\n * ┌───────────────── sign bit\n * │   ┌───────────── exponent bits\n * │   │       ┌───── fraction bits\n * │   │       │\n * X XXXXX XXXXXXXXXX\n *\n * @type {PrecisionConfigs}\n */\nconst precisionConfigs = {\n  // @see: https://en.wikipedia.org/wiki/Half-precision_floating-point_format\n  half: {\n    signBitsCount: 1,\n    exponentBitsCount: 5,\n    fractionBitsCount: 10,\n  },\n  // @see: https://en.wikipedia.org/wiki/Single-precision_floating-point_format\n  single: {\n    signBitsCount: 1,\n    exponentBitsCount: 8,\n    fractionBitsCount: 23,\n  },\n  // @see: https://en.wikipedia.org/wiki/Double-precision_floating-point_format\n  double: {\n    signBitsCount: 1,\n    exponentBitsCount: 11,\n    fractionBitsCount: 52,\n  },\n};\n\n/**\n * Converts the binary representation of the floating point number to decimal float number.\n *\n * @param {Bits} bits - sequence of bits that represents the floating point number.\n * @param {PrecisionConfig} precisionConfig - half/single/double precision config.\n * @return {number} - floating point number decoded from its binary representation.\n */\nfunction bitsToFloat(bits, precisionConfig) {\n  const { signBitsCount, exponentBitsCount } = precisionConfig;\n\n  // Figuring out the sign.\n  const sign = (-1) ** bits[0]; // -1^1 = -1, -1^0 = 1\n\n  // Calculating the exponent value.\n  const exponentBias = 2 ** (exponentBitsCount - 1) - 1;\n  const exponentBits = bits.slice(signBitsCount, signBitsCount + exponentBitsCount);\n  const exponentUnbiased = exponentBits.reduce(\n    (exponentSoFar, currentBit, bitIndex) => {\n      const bitPowerOfTwo = 2 ** (exponentBitsCount - bitIndex - 1);\n      return exponentSoFar + currentBit * bitPowerOfTwo;\n    },\n    0,\n  );\n  const exponent = exponentUnbiased - exponentBias;\n\n  // Calculating the fraction value.\n  const fractionBits = bits.slice(signBitsCount + exponentBitsCount);\n  const fraction = fractionBits.reduce(\n    (fractionSoFar, currentBit, bitIndex) => {\n      const bitPowerOfTwo = 2 ** -(bitIndex + 1);\n      return fractionSoFar + currentBit * bitPowerOfTwo;\n    },\n    0,\n  );\n\n  // Putting all parts together to calculate the final number.\n  return sign * (2 ** exponent) * (1 + fraction);\n}\n\n/**\n *  Converts the 16-bit binary representation of the floating point number to decimal float number.\n *\n * @param {Bits} bits - sequence of bits that represents the floating point number.\n * @return {number} - floating point number decoded from its binary representation.\n */\nexport function bitsToFloat16(bits) {\n  return bitsToFloat(bits, precisionConfigs.half);\n}\n\n/**\n * Converts the 32-bit binary representation of the floating point number to decimal float number.\n *\n * @param {Bits} bits - sequence of bits that represents the floating point number.\n * @return {number} - floating point number decoded from its binary representation.\n */\nexport function bitsToFloat32(bits) {\n  return bitsToFloat(bits, precisionConfigs.single);\n}\n\n/**\n * Converts the 64-bit binary representation of the floating point number to decimal float number.\n *\n * @param {Bits} bits - sequence of bits that represents the floating point number.\n * @return {number} - floating point number decoded from its binary representation.\n */\nexport function bitsToFloat64(bits) {\n  return bitsToFloat(bits, precisionConfigs.double);\n}\n"
  },
  {
    "path": "src/algorithms/math/binary-floating-point/floatAsBinaryString.js",
    "content": "// @see: https://en.wikipedia.org/wiki/Single-precision_floating-point_format\nconst singlePrecisionBytesLength = 4; // 32 bits\n\n// @see: https://en.wikipedia.org/wiki/Double-precision_floating-point_format\nconst doublePrecisionBytesLength = 8; // 64 bits\n\nconst bitsInByte = 8;\n\n/**\n * Converts the float number into its IEEE 754 binary representation.\n * @see: https://en.wikipedia.org/wiki/IEEE_754\n *\n * @param {number} floatNumber - float number in decimal format.\n * @param {number} byteLength - number of bytes to use to store the float number.\n * @return {string} - binary string representation of the float number.\n */\nfunction floatAsBinaryString(floatNumber, byteLength) {\n  let numberAsBinaryString = '';\n\n  const arrayBuffer = new ArrayBuffer(byteLength);\n  const dataView = new DataView(arrayBuffer);\n\n  const byteOffset = 0;\n  const littleEndian = false;\n\n  if (byteLength === singlePrecisionBytesLength) {\n    dataView.setFloat32(byteOffset, floatNumber, littleEndian);\n  } else {\n    dataView.setFloat64(byteOffset, floatNumber, littleEndian);\n  }\n\n  for (let byteIndex = 0; byteIndex < byteLength; byteIndex += 1) {\n    let bits = dataView.getUint8(byteIndex).toString(2);\n    if (bits.length < bitsInByte) {\n      bits = new Array(bitsInByte - bits.length).fill('0').join('') + bits;\n    }\n    numberAsBinaryString += bits;\n  }\n\n  return numberAsBinaryString;\n}\n\n/**\n * Converts the float number into its IEEE 754 64-bits binary representation.\n *\n * @param {number} floatNumber - float number in decimal format.\n * @return {string} - 64 bits binary string representation of the float number.\n */\nexport function floatAs64BinaryString(floatNumber) {\n  return floatAsBinaryString(floatNumber, doublePrecisionBytesLength);\n}\n\n/**\n * Converts the float number into its IEEE 754 32-bits binary representation.\n *\n * @param {number} floatNumber - float number in decimal format.\n * @return {string} - 32 bits binary string representation of the float number.\n */\nexport function floatAs32BinaryString(floatNumber) {\n  return floatAsBinaryString(floatNumber, singlePrecisionBytesLength);\n}\n"
  },
  {
    "path": "src/algorithms/math/binary-floating-point/testCases.js",
    "content": "/**\n * @typedef {[number, string]} TestCase\n * @property {number} decimal\n * @property {string} binary\n */\n\n/**\n * @type {TestCase[]}\n */\nexport const testCases16Bits = [\n  [-65504, '1111101111111111'],\n  [-10344, '1111000100001101'],\n  [-27.15625, '1100111011001010'],\n  [-1, '1011110000000000'],\n  [-0.09997558, '1010111001100110'],\n  [0, '0000000000000000'],\n  [5.9604644775390625e-8, '0000000000000001'],\n  [0.000004529, '0000000001001100'],\n  [0.0999755859375, '0010111001100110'],\n  [0.199951171875, '0011001001100110'],\n  [0.300048828125, '0011010011001101'],\n  [1, '0011110000000000'],\n  [1.5, '0011111000000000'],\n  [1.75, '0011111100000000'],\n  [1.875, '0011111110000000'],\n  [65504, '0111101111111111'],\n];\n\n/**\n * @type {TestCase[]}\n */\nexport const testCases32Bits = [\n  [-3.40282346638528859812e+38, '11111111011111111111111111111111'],\n  [-10345.5595703125, '11000110001000011010011000111101'],\n  [-27.15625, '11000001110110010100000000000000'],\n  [-1, '10111111100000000000000000000000'],\n  [-0.1, '10111101110011001100110011001101'],\n  [0, '00000000000000000000000000000000'],\n  [1.40129846432481707092e-45, '00000000000000000000000000000001'],\n  [0.000004560, '00110110100110010000001000011010'],\n  [0.1, '00111101110011001100110011001101'],\n  [0.2, '00111110010011001100110011001101'],\n  [0.3, '00111110100110011001100110011010'],\n  [1, '00111111100000000000000000000000'],\n  [1.5, '00111111110000000000000000000000'],\n  [1.75, '00111111111000000000000000000000'],\n  [1.875, '00111111111100000000000000000000'],\n  [3.40282346638528859812e+38, '01111111011111111111111111111111'],\n];\n\n/**\n * @type {TestCase[]}\n */\nexport const testCases64Bits = [\n  [-1.79769313486231570815e+308, '1111111111101111111111111111111111111111111111111111111111111111'],\n  [-10345.5595703125, '1100000011000100001101001100011110100000000000000000000000000000'],\n  [-27.15625, '1100000000111011001010000000000000000000000000000000000000000000'],\n  [-1, '1011111111110000000000000000000000000000000000000000000000000000'],\n  [-0.1, '1011111110111001100110011001100110011001100110011001100110011010'],\n  [0, '0000000000000000000000000000000000000000000000000000000000000000'],\n  [4.94065645841246544177e-324, '0000000000000000000000000000000000000000000000000000000000000001'],\n  [0.000004560, '0011111011010011001000000100001101000001011100110011110011100100'],\n  [0.1, '0011111110111001100110011001100110011001100110011001100110011010'],\n  [0.2, '0011111111001001100110011001100110011001100110011001100110011010'],\n  [0.3, '0011111111010011001100110011001100110011001100110011001100110011'],\n  [1, '0011111111110000000000000000000000000000000000000000000000000000'],\n  [1.5, '0011111111111000000000000000000000000000000000000000000000000000'],\n  [1.75, '0011111111111100000000000000000000000000000000000000000000000000'],\n  [1.875, '0011111111111110000000000000000000000000000000000000000000000000'],\n  [1.79769313486231570815e+308, '0111111111101111111111111111111111111111111111111111111111111111'],\n];\n"
  },
  {
    "path": "src/algorithms/math/bits/README.fr-FR.md",
    "content": "# Manipulation de bits\n\n_Read this in other languages:_\n[english](README.md).\n\n#### Vérifier un bit (_get_)\n\nCette méthode décale le bit correspondant (_bit shifting_) à la position zéro.\nEnsuite, nous exécutons l'opération `AND` avec un masque comme `0001`.\nCela efface tous les bits du nombre original sauf le correspondant.\nSi le bit pertinent est `1`, le résultat est `1`, sinon le résultat est `0`.\n\n> Voir [getBit.js](getBit.js) pour plus de détails.\n\n#### Mettre un bit à 1(_set_)\n\nCette méthode met un bit à `1` en fonction d'un rang (`bitPosition`),\ncréant ainsi une valeur qui ressemble à `00100`.\nEnsuite, nous effectuons l'opération `OU` qui met un bit spécifique\nen `1` sans affecter les autres bits du nombre.\n\n> Voir [setBit.js](setBit.js) pour plus de détails.\n\n#### Mettre un bit à 0 (_clear_)\n\nCette méthode met un bit à `1` en fonction d'un rang (`bitPosition`),\ncréant ainsi une valeur qui ressemble à `00100`.\nPuis on inverse ce masque de bits pour obtenir un nombre ressemblant à `11011`.\nEnfin, l'opération `AND` est appliquée au nombre et au masque.\nCette opération annule le bit.\n\n> Voir [clearBit.js](clearBit.js) pour plus de détails.\n\n#### Mettre à jour un Bit (_update_)\n\nCette méthode est une combinaison de l'\"annulation de bit\"\net du \"forçage de bit\".\n\n> Voir [updateBit.js](updateBit.js) pour plus de détails.\n\n#### Vérifier si un nombre est pair (_isEven_)\n\nCette méthode détermine si un nombre donné est pair.\nElle s'appuie sur le fait que les nombres impairs ont leur dernier\nbit droit à `1`.\n\n```text\nNombre: 5 = 0b0101\nisEven: false\n\nNombre: 4 = 0b0100\nisEven: true\n```\n\n> Voir [isEven.js](isEven.js) pour plus de détails.\n\n#### Vérifier si un nombre est positif (_isPositive_)\n\nCette méthode détermine un le nombre donné est positif.\nElle s'appuie sur le fait que tous les nombres positifs\nont leur bit le plus à gauche à `0`.\nCependant, si le nombre fourni est zéro\nou zéro négatif, il doit toujours renvoyer `false`.\n\n```text\nNombre: 1 = 0b0001\nisPositive: true\n\nNombre: -1 = -0b0001\nisPositive: false\n```\n\n> Voir [isPositive.js](isPositive.js) pour plus de détails.\n\n#### Multiplier par deux\n\nCette méthode décale un nombre donné d'un bit vers la gauche.\nAinsi, toutes les composantes du nombre binaire (en puissances de deux) sont\nmultipliées par deux et donc le nombre lui-même est\nmultiplié par deux.\n\n```\nAvant le décalage\nNombre: 0b0101 = 5\nPuissances de deux: 0 + 2^2 + 0 + 2^0\n\nAprès le décalage\nNombre: 0b1010 = 10\nPuissances de deux: 2^3 + 0 + 2^1 + 0\n```\n\n> Voir [multiplyByTwo.js](multiplyByTwo.js) pour plus de détails.\n\n#### Diviser par deux\n\nCette méthode décale un nombre donné d'un bit vers la droite.\nAinsi, toutes les composantes du nombre binaire (en puissances de deux) sont\ndivisées par deux et donc le nombre lui-même est\ndivisé par deux, sans reste.\n\n```\nAvant le décalage\nNombre: 0b0101 = 5\nPuissances de deux: 0 + 2^2 + 0 + 2^0\n\nAprès le décalage\nNombre: 0b0010 = 2\nPuissances de deux: 0 + 0 + 2^1 + 0\n```\n\n> Voir [divideByTwo.js](divideByTwo.js) pour plus de détails.\n\n#### Inverser le signe (_Switch Sign_)\n\nCette méthode rend positifs les nombres négatifs, et vice-versa.\nPour ce faire, elle s'appuie sur l'approche \"Complément à deux\",\nqui inverse tous les bits du nombre et y ajoute 1.\n\n```\n1101 -3\n1110 -2\n1111 -1\n0000  0\n0001  1\n0010  2\n0011  3\n```\n\n> Voir [switchSign.js](switchSign.js) pour plus de détails.\n\n#### Multiplier deux nombres signés\n\nCette méthode multiplie deux nombres entiers signés\nà l'aide d'opérateurs bit à bit.\nCette méthode est basée sur les faits suivants:\n\n```text\na * b peut être écrit sous les formes suivantes:\n  0                     si a est zero ou b est zero ou les deux sont zero\n  2a * (b/2)            si b est pair\n  2a * (b - 1)/2 + a    si b est impair et positif\n  2a * (b + 1)/2 - a    si b est impair et negatif\n```\n\nL'avantage de cette approche est qu'à chaque étape de la récursion\nl'un des opérandes est réduit à la moitié de sa valeur d'origine.\nPar conséquent, la complexité d'exécution est `O(log(b))`\noù `b` est l'opérande qui se réduit de moitié à chaque récursion.\n\n> Voir [multiply.js](multiply.js) pour plus de détails.\n\n#### Multiplier deux nombres positifs\n\nCette méthode multiplie deux nombres entiers à l'aide d'opérateurs bit à bit.\nCette méthode s'appuie sur le fait que \"Chaque nombre peut être lu\ncomme une somme de puissances de 2\".\n\nL'idée principale de la multiplication bit à bit\nest que chaque nombre peut être divisé en somme des puissances de deux:\n\nAinsi\n\n```text\n19 = 2^4 + 2^1 + 2^0\n```\n\nDonc multiplier `x` par `19` est equivalent à :\n\n```text\nx * 19 = x * 2^4 + x * 2^1 + x * 2^0\n```\n\nNous devons maintenant nous rappeler que `x * 2 ^ 4` équivaut\nà déplacer`x` vers la gauche par `4` bits (`x << 4`).\n\n> Voir [multiplyUnsigned.js](multiplyUnsigned.js) pour plus de détails.\n\n#### Compter les bits à 1\n\nThis method counts the number of set bits in a number using bitwise operators.\nThe main idea is that we shift the number right by one bit at a time and check\nthe result of `&` operation that is `1` if bit is set and `0` otherwise.\n\nCette méthode décompte les bits à `1` d'un nombre\nà l'aide d'opérateurs bit à bit.\nL'idée principale est de décaler le nombre vers la droite, un bit à la fois,\net de vérifier le résultat de l'opération `&` :\n`1` si le bit est défini et `0` dans le cas contraire.\n\n```text\nNombre: 5 = 0b0101\nDécompte des bits à 1 = 2\n```\n\n> Voir [countSetBits.js](countSetBits.js) pour plus de détails.\n\n#### Compter les bits nécessaire pour remplacer un nombre\n\nThis methods outputs the number of bits required to convert one number to another.\nThis makes use of property that when numbers are `XOR`-ed the result will be number\nof different bits.\n\nCette méthode retourne le nombre de bits requis\npour convertir un nombre en un autre.\nElle repose sur la propriété suivante:\nlorsque les nombres sont évalués via `XOR`, le résultat est le nombre\nde bits différents entre les deux.\n\n```\n5 = 0b0101\n1 = 0b0001\nNombre de bits pour le remplacement: 1\n```\n\n> Voir [bitsDiff.js](bitsDiff.js) pour plus de détails.\n\n#### Calculer les bits significatifs d'un nombre\n\nPour connaître les bits significatifs d'un nombre,\non peut décaler `1` d'un bit à gauche plusieurs fois d'affilée\njusqu'à ce que ce nombre soit plus grand que le nombre à comparer.\n\n```\n5 = 0b0101\nDécompte des bits significatifs: 3\nOn décale 1 quatre fois pour dépasser 5.\n```\n\n> Voir [bitLength.js](bitLength.js) pour plus de détails.\n\n#### Vérifier si un nombre est une puissance de 2\n\nCette méthode vérifie si un nombre donné est une puissance de deux.\nElle s'appuie sur la propriété suivante.\nDisons que `powerNumber` est une puissance de deux (c'est-à-dire 2, 4, 8, 16 etc.).\nSi nous faisons l'opération `&` entre `powerNumber` et `powerNumber - 1`,\nelle retournera`0` (dans le cas où le nombre est une puissance de deux).\n\n```\nNombre: 4 = 0b0100\nNombre: 3 = (4 - 1) = 0b0011\n4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Égal à zéro, car c'est une puissance de 2.\n\nNombre: 10 = 0b01010\nNombre: 9 = (10 - 1) = 0b01001\n10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Différent de 0, donc n'est pas une puissance de 2.\n```\n\n> Voir [isPowerOfTwo.js](isPowerOfTwo.js) pour plus de détails.\n\n#### Additionneur complet\n\nCette méthode ajoute deux nombres entiers à l'aide d'opérateurs bit à bit.\n\nElle implémente un [additionneur](https://fr.wikipedia.org/wiki/Additionneur)\nsimulant un circuit électronique logique,\npour additionner deux entiers de 32 bits,\nsous la forme « complément à deux ».\nElle utilise la logique booléenne pour couvrir tous les cas possibles\nd'ajout de deux bits donnés:\navec et sans retenue de l'ajout de l'étape précédente la moins significative.\n\nLégende:\n\n- `A`: Nombre `A`\n- `B`: Nombre `B`\n- `ai`: ième bit du nombre `A`\n- `bi`: ième bit du nombre `B`\n- `carryIn`: un bit retenu de la précédente étape la moins significative\n- `carryOut`: un bit retenu pour la prochaine étape la plus significative\n- `bitSum`: La somme de `ai`, `bi`, et `carryIn`\n- `resultBin`: Le résultat complet de l'ajout de l'étape actuelle avec toutes les étapes moins significatives (en binaire)\n- `resultDec`: Le résultat complet de l'ajout de l'étape actuelle avec toutes les étapes moins significatives (en decimal)\n\n```\nA = 3: 011\nB = 6: 110\n┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐\n│  bit │ ai │ bi │ carryIn │ carryOut │  bitSum │ resultBin │ resultDec │\n├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤\n│   0  │ 1  │ 0  │    0    │    0     │     1   │       1   │     1     │\n│   1  │ 1  │ 1  │    0    │    1     │     0   │      01   │     1     │\n│   2  │ 0  │ 1  │    1    │    1     │     0   │     001   │     1     │\n│   3  │ 0  │ 0  │    1    │    0     │     1   │    1001   │     9     │\n└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘\n```\n\n> Voir [fullAdder.js](fullAdder.js) pour plus de détails.  \n> Voir [Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).\n\n## Références\n\n- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)\n"
  },
  {
    "path": "src/algorithms/math/bits/README.md",
    "content": "# Bit Manipulation\n\n_Read this in other languages:_\n[français](README.fr-FR.md),\n[简体中文](README.zh-CN.md).\n\n#### Get Bit\n\nThis method shifts the relevant bit to the zeroth position.\nThen we perform `AND` operation with one which has bit\npattern like `0001`. This clears all bits from the original\nnumber except the relevant one. If the relevant bit is one,\nthe result is `1`, otherwise the result is `0`.\n\n> See [getBit.js](getBit.js) for further details.\n\n#### Set Bit\n\nThis method shifts `1` over by `bitPosition` bits, creating a\nvalue that looks like `00100`. Then we perform `OR` operation\nthat sets specific bit into `1` but it does not affect on\nother bits of the number.\n\n> See [setBit.js](setBit.js) for further details.\n\n#### Clear Bit\n\nThis method shifts `1` over by `bitPosition` bits, creating a\nvalue that looks like `00100`. Than it inverts this mask to get\nthe number that looks like `11011`. Then `AND` operation is\nbeing applied to both the number and the mask. That operation\nunsets the bit.\n\n> See [clearBit.js](clearBit.js) for further details.\n\n#### Update Bit\n\nThis method is a combination of \"Clear Bit\" and \"Set Bit\" methods.\n\n> See [updateBit.js](updateBit.js) for further details.\n\n#### isEven\n\nThis method determines if the number provided is even.\nIt is based on the fact that odd numbers have their last\nright bit to be set to 1.\n\n```text\nNumber: 5 = 0b0101\nisEven: false\n\nNumber: 4 = 0b0100\nisEven: true\n```\n\n> See [isEven.js](isEven.js) for further details.\n\n#### isPositive\n\nThis method determines if the number is positive. It is based on the fact that all positive\nnumbers have their leftmost bit to be set to `0`. However, if the number provided is zero\nor negative zero, it should still return `false`.\n\n```text\nNumber: 1 = 0b0001\nisPositive: true\n\nNumber: -1 = -0b0001\nisPositive: false\n```\n\n> See [isPositive.js](isPositive.js) for further details.\n\n#### Multiply By Two\n\nThis method shifts original number by one bit to the left.\nThus all binary number components (powers of two) are being\nmultiplying by two and thus the number itself is being\nmultiplied by two.\n\n```\nBefore the shift\nNumber: 0b0101 = 5\nPowers of two: 0 + 2^2 + 0 + 2^0\n\nAfter the shift\nNumber: 0b1010 = 10\nPowers of two: 2^3 + 0 + 2^1 + 0\n```\n\n> See [multiplyByTwo.js](multiplyByTwo.js) for further details.\n\n#### Divide By Two\n\nThis method shifts original number by one bit to the right.\nThus all binary number components (powers of two) are being\ndivided by two and thus the number itself is being\ndivided by two without remainder.\n\n```\nBefore the shift\nNumber: 0b0101 = 5\nPowers of two: 0 + 2^2 + 0 + 2^0\n\nAfter the shift\nNumber: 0b0010 = 2\nPowers of two: 0 + 0 + 2^1 + 0\n```\n\n> See [divideByTwo.js](divideByTwo.js) for further details.\n\n#### Switch Sign\n\nThis method make positive numbers to be negative and backwards.\nTo do so it uses \"Twos Complement\" approach which does it by\ninverting all of the bits of the number and adding 1 to it.\n\n```\n1101 -3\n1110 -2\n1111 -1\n0000  0\n0001  1\n0010  2\n0011  3\n```\n\n> See [switchSign.js](switchSign.js) for further details.\n\n#### Multiply Two Signed Numbers\n\nThis method multiplies two signed integer numbers using bitwise operators.\nThis method is based on the following facts:\n\n```text\na * b can be written in the below formats:\n  0                     if a is zero or b is zero or both a and b are zeroes\n  2a * (b/2)            if b is even\n  2a * (b - 1)/2 + a    if b is odd and positive\n  2a * (b + 1)/2 - a    if b is odd and negative\n```\n\nThe advantage of this approach is that in each recursive step one of the operands\nreduces to half its original value. Hence, the run time complexity is `O(log(b))` where `b` is\nthe operand that reduces to half on each recursive step.\n\n> See [multiply.js](multiply.js) for further details.\n\n#### Multiply Two Unsigned Numbers\n\nThis method multiplies two integer numbers using bitwise operators.\nThis method is based on that \"Every number can be denoted as the sum of powers of 2\".\n\nThe main idea of bitwise multiplication is that every number may be split\nto the sum of powers of two:\n\nI.e.\n\n```text\n19 = 2^4 + 2^1 + 2^0\n```\n\nThen multiplying number `x` by `19` is equivalent of:\n\n```text\nx * 19 = x * 2^4 + x * 2^1 + x * 2^0\n```\n\nNow we need to remember that `x * 2^4` is equivalent of shifting `x` left\nby `4` bits (`x << 4`).\n\n> See [multiplyUnsigned.js](multiplyUnsigned.js) for further details.\n\n#### Count Set Bits\n\nThis method counts the number of set bits in a number using bitwise operators.\nThe main idea is that we shift the number right by one bit at a time and check\nthe result of `&` operation that is `1` if bit is set and `0` otherwise.\n\n```text\nNumber: 5 = 0b0101\nCount of set bits = 2\n```\n\n> See [countSetBits.js](countSetBits.js) for further details.\n\n#### Count Bits to Flip One Number to Another\n\nThis methods outputs the number of bits required to convert one number to another.\nThis makes use of property that when numbers are `XOR`-ed the result will be number\nof different bits.\n\n```\n5 = 0b0101\n1 = 0b0001\nCount of Bits to be Flipped: 1\n```\n\n> See [bitsDiff.js](bitsDiff.js) for further details.\n\n#### Count Bits of a Number\n\nTo calculate the number of valuable bits we need to shift `1` one bit left each\ntime and see if shifted number is bigger than the input number.\n\n```\n5 = 0b0101\nCount of valuable bits is: 3\nWhen we shift 1 four times it will become bigger than 5.\n```\n\n> See [bitLength.js](bitLength.js) for further details.\n\n#### Is Power of Two\n\nThis method checks if a number provided is power of two. It uses the following\nproperty. Let's say that `powerNumber` is a number that has been formed as a power\nof two (i.e. 2, 4, 8, 16 etc.). Then if we'll do `&` operation between `powerNumber`\nand `powerNumber - 1` it will return `0` (in case if number is power of two).\n\n```\nNumber: 4 = 0b0100\nNumber: 3 = (4 - 1) = 0b0011\n4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Equal to zero, is power of two.\n\nNumber: 10 = 0b01010\nNumber: 9 = (10 - 1) = 0b01001\n10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Not equal to zero, not a power of two.\n```\n\n> See [isPowerOfTwo.js](isPowerOfTwo.js) for further details.\n\n#### Full Adder\n\nThis method adds up two integer numbers using bitwise operators.\n\nIt implements [full adder](<https://en.wikipedia.org/wiki/Adder_(electronics)>)\nelectronics circuit logic to sum two 32-bit integers in two's complement format.\nIt's using the boolean logic to cover all possible cases of adding two input bits:\nwith and without a \"carry bit\" from adding the previous less-significant stage.\n\nLegend:\n\n- `A`: Number `A`\n- `B`: Number `B`\n- `ai`: ith bit of number `A`\n- `bi`: ith bit of number `B`\n- `carryIn`: a bit carried in from the previous less-significant stage\n- `carryOut`: a bit to carry to the next most-significant stage\n- `bitSum`: The sum of `ai`, `bi`, and `carryIn`\n- `resultBin`: The full result of adding current stage with all less-significant stages (in binary)\n- `resultDec`: The full result of adding current stage with all less-significant stages (in decimal)\n\n```\nA = 3: 011\nB = 6: 110\n┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐\n│  bit │ ai │ bi │ carryIn │ carryOut │  bitSum │ resultBin │ resultDec │\n├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤\n│   0  │ 1  │ 0  │    0    │    0     │     1   │       1   │     1     │\n│   1  │ 1  │ 1  │    0    │    1     │     0   │      01   │     1     │\n│   2  │ 0  │ 1  │    1    │    1     │     0   │     001   │     1     │\n│   3  │ 0  │ 0  │    1    │    0     │     1   │    1001   │     9     │\n└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘\n```\n\n> See [fullAdder.js](fullAdder.js) for further details.\n> See [Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).\n\n## References\n\n- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)\n"
  },
  {
    "path": "src/algorithms/math/bits/README.zh-CN.md",
    "content": "# 位运算\n\n_Read this in other languages:_\n[français](README.fr-FR.md),\n[english](README.md)\n\n#### Get Bit\n\n该方法向右移动目标位到最右边，即位数组的第0个位置上。然后在该数上与形如 `0001`的二进制形式的数进行`AND`操作。这会清理掉除了目标位的所有其它位的数据。如果目标位是1，那么结果就是`1`，反之，结果是`0`;\n\n> 查看[getBit.js](getBit.js)了解更多细节。\n\n#### Set Bit\n\n该方法把`1`向左移动了`bitPosition`位，生成了一个二进制形如`00100`的值。然后我们拿该值与目标数字进行`OR`操作，就能把目标位设置位`1`而不影响其它位。\n\n> 查看[setBit.js](setBit.js)了解更多细节。\n\n#### Clear Bit\n\n该方法把`1`向左移动了`bitPosition`位，生成了一个二进制形如`00100`的值。然后反转每一位的数字，得到一个二进制形如`11011`的值。接着与目标值进行`AND`操作，就能清除掉目标位的值。\n\n> 查看[clearBit.js](clearBit.js)了解更多细节。\n\n#### Update Bit\n\n该方法组合了“Clear Bit”和“Set Bit”\n\n> 查看[updateBit.js](updateBit.js)了解更多细节。\n\n#### isEven\n\n该方法检测传入的number是否是偶数。它的实现基于奇数的最右边的位永远是`1`这个事实。\n\n```text\nNumber: 5 = 0b0101\nisEven: false\n\nNumber: 4 = 0b0100\nisEven: true\n```\n\n> 查看[isEven.js](isEven.js)了解更多细节。\n\n#### isPositive\n\n该方法检测传入的number是否是正数。它的实现基于正数最左边的位永远是`0`这个事实。然而如果传入的number是0或者-0，它也应该返回false。\n\n```text\nNumber: 1 = 0b0001\nisPositive: true\n\nNumber: -1 = -0b0001\nisPositive: false\n```\n\n> 查看[isPositive.js](isPositive.js)了解更多细节。\n\n#### Multiply By Two\n\n该方法将原始数字向左移动一位。因此所有位都将乘以2，因此数字本身也将乘以2。\n\n```\nBefore the shift\nNumber: 0b0101 = 5\nPowers of two: 0 + 2^2 + 0 + 2^0\n\nAfter the shift\nNumber: 0b1010 = 10\nPowers of two: 2^3 + 0 + 2^1 + 0\n```\n\n> 查看[multiplyByTwo.js](multiplyByTwo.js)了解更多细节。\n\n#### Divide By Two\n\n该方法将原始数字向右移动一位。因此所有位都将除以2，因此数字本身也将除以2,且不会产生余数。\n\n```\nBefore the shift\nNumber: 0b0101 = 5\nPowers of two: 0 + 2^2 + 0 + 2^0\n\nAfter the shift\nNumber: 0b0010 = 2\nPowers of two: 0 + 0 + 2^1 + 0\n```\n\n> 查看[divideByTwo.js](divideByTwo.js)了解更多细节。\n\n#### Switch Sign\n\n该方法将正数变成负数，反之亦然。为了做到这一点，它使用了“二进制补码”的方法，即取反所有位然后加1.\n\n```\n1101 -3\n1110 -2\n1111 -1\n0000  0\n0001  1\n0010  2\n0011  3\n```\n\n> 查看[switchSign.js](switchSign.js)了解更多细节。\n\n#### Multiply Two Signed Numbers\n\n该方法使用位运算符计算两个有符号数的乘积。实现基于以下事实：\n\n```text\na * b 可以被改写成如下形式:\n  0                     a为0，b为0，或者a，b都为0\n  2a * (b/2)            b是偶数\n  2a * (b - 1)/2 + a    b是奇数，正数\n  2a * (b + 1)/2 - a    b是奇数，负数\n```\n\n这样转换的优势在于，递归的每一步，递归的操作数的值都减少了一半。因此，运行时的时间复杂度为`O(log(b))`,其中b是在每个递归步骤上减少为一半的操作数。\n\n\n> 查看[multiply.js](multiply.js)了解更多细节。\n\n#### Multiply Two Unsigned Numbers\n\n该方法使用位运算符计算两个无符号数的乘积。实现基于“每个数字都可以表示为一系列2的幂的和”。\n\n逐位乘法的主要思想是，每个数字都可以拆分为两个乘方的和：\n\n比如：\n\n```text\n19 = 2^4 + 2^1 + 2^0\n```\n\n然后`19`乘`x`就等价于：\n\n```text\nx * 19 = x * 2^4 + x * 2^1 + x * 2^0\n```\n\n接着我们应该意识到`x*2^4`是等价于`x`向左移动`4`位（`x << 4`）的;\n\n> 查看[multiplyUnsigned.js](multiplyUnsigned.js)了解更多细节。\n\n#### Count Set Bits\n\n该方法使用位运算符对一个数字里设置为`1`的位进行记数。主要方法是，把数字每次向右移动1位，然后使用`&`操作符取出最右边一位的值，`1`则记数加1，`0`则不计。\n\n```text\nNumber: 5 = 0b0101\nCount of set bits = 2\n```\n\n> 查看[countSetBits.js](countSetBits.js)了解更多细节。\n\n#### Count Bits to Flip One Number to Another\n\n\n该方法输出把一个数字转换为另一个数字所需要转换的位数。这利用了以下特性：当数字进行`XOR`异或运算时，结果将是不同位数的数量(即异或的结果中所有被设置为1的位的数量)。\n\n```\n5 = 0b0101\n1 = 0b0001\nCount of Bits to be Flipped: 1\n```\n\n> 查看[bitsDiff.js](bitsDiff.js)了解更多细节。\n\n#### Count Bits of a Number\n\n为了计算数字的有效位数，我们需要把`1`每次向左移动一位，然后检查产生的值是否大于输入的数字。\n\n```\n5 = 0b0101\n有效位数: 3\n当我们把1向左移动4位的时候，会大于5.\n```\n\n> 查看[bitLength.js](bitLength.js)了解更多细节。\n\n#### Is Power of Two\n\n该方法检测数字是否可以表示为2的幂。它使用了以下特性，我们定义`powerNumber`是可以写成2的幂的形式的数(2,4,8,16 etc.)。然后我们会把`powerNumber`和`powerNumber - 1`进行`&`操作，它会返回`0`(如果该数字可以表示为2的幂)。\n\n```\nNumber: 4 = 0b0100\nNumber: 3 = (4 - 1) = 0b0011\n4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Equal to zero, is power of two.\n\nNumber: 10 = 0b01010\nNumber: 9 = (10 - 1) = 0b01001\n10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Not equal to zero, not a power of two.\n```\n\n> 查看[isPowerOfTwo.js](isPowerOfTwo.js)了解更多细节。\n\n#### Full Adder\n\n该方法使用位运算符计算两个数的和。\n\n它实现了[完整的加法器](<https://en.wikipedia.org/wiki/Adder_(electronics)>)电子电路逻辑，以补码的形式计算两个32位数字的和。它使用布尔逻辑来覆盖了两个位相加的所有情况：从前一位相加的时候，产没产生进位“carry bit”。\n\nLegend:\n\n- `A`: 数字 `A`\n- `B`: 数字 `B`\n- `ai`: 数字`A`以二进制表示时的位下标\n- `bi`: 数字`B`以二进制表示时的位下标\n- `carryIn`: 本次计算产生的进位\n- `carryOut`: 带入此次计算的进位\n- `bitSum`: `ai`, `bi`, 和 `carryIn` 的和\n- `resultBin`: 当前计算的结果（二进制形式）\n- `resultDec`: 当前计算的结果（十进制形式）\n\n```\nA = 3: 011\nB = 6: 110\n┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐\n│  bit │ ai │ bi │ carryIn │ carryOut │  bitSum │ resultBin │ resultDec │\n├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤\n│   0  │ 1  │ 0  │    0    │    0     │     1   │       1   │     1     │\n│   1  │ 1  │ 1  │    0    │    1     │     0   │      01   │     1     │\n│   2  │ 0  │ 1  │    1    │    1     │     0   │     001   │     1     │\n│   3  │ 0  │ 0  │    1    │    0     │     1   │    1001   │     9     │\n└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘\n```\n\n> 查看[fullAdder.js](fullAdder.js)了解更多细节。  \n> 查看[Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).\n\n## References\n\n- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/bitLength.test.js",
    "content": "import bitLength from '../bitLength';\n\ndescribe('bitLength', () => {\n  it('should calculate number of bits that the number is consists of', () => {\n    expect(bitLength(0b0)).toBe(0);\n    expect(bitLength(0b1)).toBe(1);\n    expect(bitLength(0b01)).toBe(1);\n    expect(bitLength(0b101)).toBe(3);\n    expect(bitLength(0b0101)).toBe(3);\n    expect(bitLength(0b10101)).toBe(5);\n    expect(bitLength(0b11110101)).toBe(8);\n    expect(bitLength(0b00011110101)).toBe(8);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/bitsDiff.test.js",
    "content": "import bitsDiff from '../bitsDiff';\n\ndescribe('bitsDiff', () => {\n  it('should calculate bits difference between two numbers', () => {\n    expect(bitsDiff(0, 0)).toBe(0);\n    expect(bitsDiff(1, 1)).toBe(0);\n    expect(bitsDiff(124, 124)).toBe(0);\n    expect(bitsDiff(0, 1)).toBe(1);\n    expect(bitsDiff(1, 0)).toBe(1);\n    expect(bitsDiff(1, 2)).toBe(2);\n    expect(bitsDiff(1, 3)).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/clearBit.test.js",
    "content": "import clearBit from '../clearBit';\n\ndescribe('clearBit', () => {\n  it('should clear bit at specific position', () => {\n    // 1 = 0b0001\n    expect(clearBit(1, 0)).toBe(0);\n    expect(clearBit(1, 1)).toBe(1);\n    expect(clearBit(1, 2)).toBe(1);\n\n    // 10 = 0b1010\n    expect(clearBit(10, 0)).toBe(10);\n    expect(clearBit(10, 1)).toBe(8);\n    expect(clearBit(10, 3)).toBe(2);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/countSetBits.test.js",
    "content": "import countSetBits from '../countSetBits';\n\ndescribe('countSetBits', () => {\n  it('should return number of set bits', () => {\n    expect(countSetBits(0)).toBe(0);\n    expect(countSetBits(1)).toBe(1);\n    expect(countSetBits(2)).toBe(1);\n    expect(countSetBits(3)).toBe(2);\n    expect(countSetBits(4)).toBe(1);\n    expect(countSetBits(5)).toBe(2);\n    expect(countSetBits(21)).toBe(3);\n    expect(countSetBits(255)).toBe(8);\n    expect(countSetBits(1023)).toBe(10);\n    expect(countSetBits(-1)).toBe(32);\n    expect(countSetBits(-21)).toBe(30);\n    expect(countSetBits(-255)).toBe(25);\n    expect(countSetBits(-1023)).toBe(23);\n    expect(countSetBits(-4294967296)).toBe(0);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/divideByTwo.test.js",
    "content": "import divideByTwo from '../divideByTwo';\n\ndescribe('divideByTwo', () => {\n  it('should divide numbers by two using bitwise operations', () => {\n    expect(divideByTwo(0)).toBe(0);\n    expect(divideByTwo(1)).toBe(0);\n    expect(divideByTwo(3)).toBe(1);\n    expect(divideByTwo(10)).toBe(5);\n    expect(divideByTwo(17)).toBe(8);\n    expect(divideByTwo(125)).toBe(62);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/fullAdder.test.js",
    "content": "import fullAdder from '../fullAdder';\n\ndescribe('fullAdder', () => {\n  it('should add up two numbers', () => {\n    expect(fullAdder(0, 0)).toBe(0);\n    expect(fullAdder(2, 0)).toBe(2);\n    expect(fullAdder(0, 2)).toBe(2);\n    expect(fullAdder(1, 2)).toBe(3);\n    expect(fullAdder(2, 1)).toBe(3);\n    expect(fullAdder(6, 6)).toBe(12);\n    expect(fullAdder(-2, 4)).toBe(2);\n    expect(fullAdder(4, -2)).toBe(2);\n    expect(fullAdder(-4, -4)).toBe(-8);\n    expect(fullAdder(4, -5)).toBe(-1);\n    expect(fullAdder(2, 121)).toBe(123);\n    expect(fullAdder(121, 2)).toBe(123);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/getBit.test.js",
    "content": "import getBit from '../getBit';\n\ndescribe('getBit', () => {\n  it('should get bit at specific position', () => {\n    // 1 = 0b0001\n    expect(getBit(1, 0)).toBe(1);\n    expect(getBit(1, 1)).toBe(0);\n\n    // 2 = 0b0010\n    expect(getBit(2, 0)).toBe(0);\n    expect(getBit(2, 1)).toBe(1);\n\n    // 3 = 0b0011\n    expect(getBit(3, 0)).toBe(1);\n    expect(getBit(3, 1)).toBe(1);\n\n    // 10 = 0b1010\n    expect(getBit(10, 0)).toBe(0);\n    expect(getBit(10, 1)).toBe(1);\n    expect(getBit(10, 2)).toBe(0);\n    expect(getBit(10, 3)).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/isEven.test.js",
    "content": "import isEven from '../isEven';\n\ndescribe('isEven', () => {\n  it('should detect if a number is even', () => {\n    expect(isEven(0)).toBe(true);\n    expect(isEven(2)).toBe(true);\n    expect(isEven(-2)).toBe(true);\n    expect(isEven(1)).toBe(false);\n    expect(isEven(-1)).toBe(false);\n    expect(isEven(-3)).toBe(false);\n    expect(isEven(3)).toBe(false);\n    expect(isEven(8)).toBe(true);\n    expect(isEven(9)).toBe(false);\n    expect(isEven(121)).toBe(false);\n    expect(isEven(122)).toBe(true);\n    expect(isEven(1201)).toBe(false);\n    expect(isEven(1202)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/isPositive.test.js",
    "content": "import isPositive from '../isPositive';\n\ndescribe('isPositive', () => {\n  it('should detect if a number is positive', () => {\n    expect(isPositive(1)).toBe(true);\n    expect(isPositive(2)).toBe(true);\n    expect(isPositive(3)).toBe(true);\n    expect(isPositive(5665)).toBe(true);\n    expect(isPositive(56644325)).toBe(true);\n\n    expect(isPositive(0)).toBe(false);\n    expect(isPositive(-0)).toBe(false);\n    expect(isPositive(-1)).toBe(false);\n    expect(isPositive(-2)).toBe(false);\n    expect(isPositive(-126)).toBe(false);\n    expect(isPositive(-5665)).toBe(false);\n    expect(isPositive(-56644325)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/isPowerOfTwo.test.js",
    "content": "import isPowerOfTwo from '../isPowerOfTwo';\n\ndescribe('isPowerOfTwo', () => {\n  it('should detect if the number is power of two', () => {\n    expect(isPowerOfTwo(1)).toBe(true);\n    expect(isPowerOfTwo(2)).toBe(true);\n    expect(isPowerOfTwo(3)).toBe(false);\n    expect(isPowerOfTwo(4)).toBe(true);\n    expect(isPowerOfTwo(5)).toBe(false);\n    expect(isPowerOfTwo(6)).toBe(false);\n    expect(isPowerOfTwo(7)).toBe(false);\n    expect(isPowerOfTwo(8)).toBe(true);\n    expect(isPowerOfTwo(9)).toBe(false);\n    expect(isPowerOfTwo(16)).toBe(true);\n    expect(isPowerOfTwo(23)).toBe(false);\n    expect(isPowerOfTwo(32)).toBe(true);\n    expect(isPowerOfTwo(127)).toBe(false);\n    expect(isPowerOfTwo(128)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/multiply.test.js",
    "content": "import multiply from '../multiply';\n\ndescribe('multiply', () => {\n  it('should multiply two numbers', () => {\n    expect(multiply(0, 0)).toBe(0);\n    expect(multiply(2, 0)).toBe(0);\n    expect(multiply(0, 2)).toBe(0);\n    expect(multiply(1, 2)).toBe(2);\n    expect(multiply(2, 1)).toBe(2);\n    expect(multiply(6, 6)).toBe(36);\n    expect(multiply(-2, 4)).toBe(-8);\n    expect(multiply(4, -2)).toBe(-8);\n    expect(multiply(-4, -4)).toBe(16);\n    expect(multiply(4, -5)).toBe(-20);\n    expect(multiply(2, 121)).toBe(242);\n    expect(multiply(121, 2)).toBe(242);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/multiplyByTwo.test.js",
    "content": "import multiplyByTwo from '../multiplyByTwo';\n\ndescribe('multiplyByTwo', () => {\n  it('should multiply numbers by two using bitwise operations', () => {\n    expect(multiplyByTwo(0)).toBe(0);\n    expect(multiplyByTwo(1)).toBe(2);\n    expect(multiplyByTwo(3)).toBe(6);\n    expect(multiplyByTwo(10)).toBe(20);\n    expect(multiplyByTwo(17)).toBe(34);\n    expect(multiplyByTwo(125)).toBe(250);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/multiplyUnsigned.test.js",
    "content": "import multiplyUnsigned from '../multiplyUnsigned';\n\ndescribe('multiplyUnsigned', () => {\n  it('should multiply two unsigned numbers', () => {\n    expect(multiplyUnsigned(0, 2)).toBe(0);\n    expect(multiplyUnsigned(2, 0)).toBe(0);\n    expect(multiplyUnsigned(1, 1)).toBe(1);\n    expect(multiplyUnsigned(1, 2)).toBe(2);\n    expect(multiplyUnsigned(2, 7)).toBe(14);\n    expect(multiplyUnsigned(7, 2)).toBe(14);\n    expect(multiplyUnsigned(30, 2)).toBe(60);\n    expect(multiplyUnsigned(17, 34)).toBe(578);\n    expect(multiplyUnsigned(170, 2340)).toBe(397800);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/setBit.test.js",
    "content": "import setBit from '../setBit';\n\ndescribe('setBit', () => {\n  it('should set bit at specific position', () => {\n    // 1 = 0b0001\n    expect(setBit(1, 0)).toBe(1);\n    expect(setBit(1, 1)).toBe(3);\n    expect(setBit(1, 2)).toBe(5);\n\n    // 10 = 0b1010\n    expect(setBit(10, 0)).toBe(11);\n    expect(setBit(10, 1)).toBe(10);\n    expect(setBit(10, 2)).toBe(14);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/switchSign.test.js",
    "content": "import switchSign from '../switchSign';\n\ndescribe('switchSign', () => {\n  it('should switch the sign of the number using twos complement approach', () => {\n    expect(switchSign(0)).toBe(0);\n    expect(switchSign(1)).toBe(-1);\n    expect(switchSign(-1)).toBe(1);\n    expect(switchSign(32)).toBe(-32);\n    expect(switchSign(-32)).toBe(32);\n    expect(switchSign(23)).toBe(-23);\n    expect(switchSign(-23)).toBe(23);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/__test__/updateBit.test.js",
    "content": "import updateBit from '../updateBit';\n\ndescribe('updateBit', () => {\n  it('should update bit at specific position', () => {\n    // 1 = 0b0001\n    expect(updateBit(1, 0, 1)).toBe(1);\n    expect(updateBit(1, 0, 0)).toBe(0);\n    expect(updateBit(1, 1, 1)).toBe(3);\n    expect(updateBit(1, 2, 1)).toBe(5);\n\n    // 10 = 0b1010\n    expect(updateBit(10, 0, 1)).toBe(11);\n    expect(updateBit(10, 0, 0)).toBe(10);\n    expect(updateBit(10, 1, 1)).toBe(10);\n    expect(updateBit(10, 1, 0)).toBe(8);\n    expect(updateBit(10, 2, 1)).toBe(14);\n    expect(updateBit(10, 2, 0)).toBe(10);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/bits/bitLength.js",
    "content": "/**\n * Return the number of bits used in the binary representation of the number.\n *\n * @param {number} number\n * @return {number}\n */\nexport default function bitLength(number) {\n  let bitsCounter = 0;\n\n  while ((1 << bitsCounter) <= number) {\n    bitsCounter += 1;\n  }\n\n  return bitsCounter;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/bitsDiff.js",
    "content": "import countSetBits from './countSetBits';\n\n/**\n * Counts the number of bits that need to be change in order\n * to convert numberA to numberB.\n *\n * @param {number} numberA\n * @param {number} numberB\n * @return {number}\n */\nexport default function bitsDiff(numberA, numberB) {\n  return countSetBits(numberA ^ numberB);\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/clearBit.js",
    "content": "/**\n * @param {number} number\n * @param {number} bitPosition - zero based.\n * @return {number}\n */\nexport default function clearBit(number, bitPosition) {\n  const mask = ~(1 << bitPosition);\n\n  return number & mask;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/countSetBits.js",
    "content": "/**\n * @param {number} originalNumber\n * @return {number}\n */\nexport default function countSetBits(originalNumber) {\n  let setBitsCount = 0;\n  let number = originalNumber;\n\n  while (number) {\n    // Add last bit of the number to the sum of set bits.\n    setBitsCount += number & 1;\n\n    // Shift number right by one bit to investigate other bits.\n    number >>>= 1;\n  }\n\n  return setBitsCount;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/divideByTwo.js",
    "content": "/**\n * @param {number} number\n * @return {number}\n */\nexport default function divideByTwo(number) {\n  return number >> 1;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/fullAdder.js",
    "content": "import getBit from './getBit';\n\n/**\n * Add two numbers using only binary operators.\n *\n * This is an implementation of full adders logic circuit.\n * https://en.wikipedia.org/wiki/Adder_(electronics)\n * Inspired by: https://www.youtube.com/watch?v=wvJc9CZcvBc\n *\n * Table(1)\n *  INPUT  | OUT\n *  C Ai Bi | C Si | Row\n * -------- | -----| ---\n *  0  0  0 | 0  0 | 1\n *  0  0  1 | 0  1 | 2\n *  0  1  0 | 0  1 | 3\n *  0  1  1 | 1  0 | 4\n * -------- | ---- | --\n *  1  0  0 | 0  1 | 5\n *  1  0  1 | 1  0 | 6\n *  1  1  0 | 1  0 | 7\n *  1  1  1 | 1  1 | 8\n * ---------------------\n *\n * Legend:\n * INPUT C = Carry in, from the previous less-significant stage\n * INPUT Ai = ith bit of Number A\n * INPUT Bi = ith bit of Number B\n * OUT C = Carry out to the next most-significant stage\n * OUT Si = Bit Sum, ith least significant bit of the result\n *\n *\n * @param {number} a\n * @param {number} b\n * @return {number}\n */\nexport default function fullAdder(a, b) {\n  let result = 0;\n  let carry = 0;\n\n  // The operands of all bitwise operators are converted to signed\n  // 32-bit integers in two's complement format.\n  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Signed_32-bit_integers\n  for (let i = 0; i < 32; i += 1) {\n    const ai = getBit(a, i);\n    const bi = getBit(b, i);\n    const carryIn = carry;\n\n    // Calculate binary Ai + Bi without carry (half adder)\n    // See Table(1) rows 1 - 4: Si = Ai ^ Bi\n    const aiPlusBi = ai ^ bi;\n\n    // Calculate ith bit of the result by adding the carry bit to Ai + Bi\n    // For Table(1) rows 5 - 8 carryIn = 1: Si = Ai ^ Bi ^ 1, flip the bit\n    // Fpr Table(1) rows 1 - 4 carryIn = 0: Si = Ai ^ Bi ^ 0, a no-op.\n    const bitSum = aiPlusBi ^ carryIn;\n\n    // Carry out one to the next most-significant stage\n    // when at least one of these is true:\n    // 1) Table(1) rows 6, 7: one of Ai OR Bi is 1 AND carryIn = 1\n    // 2) Table(1) rows 4, 8: Both Ai AND Bi are 1\n    const carryOut = (aiPlusBi & carryIn) | (ai & bi);\n    carry = carryOut;\n\n    // Set ith least significant bit of the result to bitSum.\n    result |= bitSum << i;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/getBit.js",
    "content": "/**\n * @param {number} number\n * @param {number} bitPosition - zero based.\n * @return {number}\n */\nexport default function getBit(number, bitPosition) {\n  return (number >> bitPosition) & 1;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/isEven.js",
    "content": "/**\n * @param {number} number\n * @return {boolean}\n */\nexport default function isEven(number) {\n  return (number & 1) === 0;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/isPositive.js",
    "content": "/**\n * @param {number} number - 32-bit integer.\n * @return {boolean}\n */\nexport default function isPositive(number) {\n  // Zero is neither a positive nor a negative number.\n  if (number === 0) {\n    return false;\n  }\n\n  // The most significant 32nd bit can be used to determine whether the number is positive.\n  return ((number >> 31) & 1) === 0;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/isPowerOfTwo.js",
    "content": "/**\n * @param {number} number\n * @return bool\n */\nexport default function isPowerOfTwo(number) {\n  return (number & (number - 1)) === 0;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/multiply.js",
    "content": "import multiplyByTwo from './multiplyByTwo';\nimport divideByTwo from './divideByTwo';\nimport isEven from './isEven';\nimport isPositive from './isPositive';\n\n/**\n * Multiply two signed numbers using bitwise operations.\n *\n * If a is zero or b is zero or if both a and b are zeros:\n * multiply(a, b) = 0\n *\n * If b is even:\n * multiply(a, b) = multiply(2a, b/2)\n *\n * If b is odd and b is positive:\n * multiply(a, b) = multiply(2a, (b-1)/2) + a\n *\n * If b is odd and b is negative:\n * multiply(a, b) = multiply(2a, (b+1)/2) - a\n *\n * Time complexity: O(log b)\n *\n * @param {number} a\n * @param {number} b\n * @return {number}\n */\nexport default function multiply(a, b) {\n  // If a is zero or b is zero or if both a and b are zeros then the production is also zero.\n  if (b === 0 || a === 0) {\n    return 0;\n  }\n\n  // Otherwise we will have four different cases that are described above.\n  const multiplyByOddPositive = () => multiply(multiplyByTwo(a), divideByTwo(b - 1)) + a;\n  const multiplyByOddNegative = () => multiply(multiplyByTwo(a), divideByTwo(b + 1)) - a;\n\n  const multiplyByEven = () => multiply(multiplyByTwo(a), divideByTwo(b));\n  const multiplyByOdd = () => (isPositive(b) ? multiplyByOddPositive() : multiplyByOddNegative());\n\n  return isEven(b) ? multiplyByEven() : multiplyByOdd();\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/multiplyByTwo.js",
    "content": "/**\n * @param {number} number\n * @return {number}\n */\nexport default function multiplyByTwo(number) {\n  return number << 1;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/multiplyUnsigned.js",
    "content": "/**\n * Multiply to unsigned numbers using bitwise operator.\n *\n * The main idea of bitwise multiplication is that every number may be split\n * to the sum of powers of two:\n *\n * I.e. 19 = 2^4 + 2^1 + 2^0\n *\n * Then multiplying number x by 19 is equivalent of:\n *\n * x * 19 = x * 2^4 + x * 2^1 + x * 2^0\n *\n * Now we need to remember that (x * 2^4) is equivalent of shifting x left by 4 bits (x << 4).\n *\n * @param {number} number1\n * @param {number} number2\n * @return {number}\n */\nexport default function multiplyUnsigned(number1, number2) {\n  let result = 0;\n\n  // Let's treat number2 as a multiplier for the number1.\n  let multiplier = number2;\n\n  // Multiplier current bit index.\n  let bitIndex = 0;\n\n  // Go through all bits of number2.\n  while (multiplier !== 0) {\n    // Check if current multiplier bit is set.\n    if (multiplier & 1) {\n      // In case if multiplier's bit at position bitIndex is set\n      // it would mean that we need to multiply number1 by the power\n      // of bit with index bitIndex and then add it to the result.\n      result += (number1 << bitIndex);\n    }\n\n    bitIndex += 1;\n    multiplier >>= 1;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/setBit.js",
    "content": "/**\n * @param {number} number\n * @param {number} bitPosition - zero based.\n * @return {number}\n */\nexport default function setBit(number, bitPosition) {\n  return number | (1 << bitPosition);\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/switchSign.js",
    "content": "/**\n * Switch the sign of the number using \"Twos Complement\" approach.\n * @param {number} number\n * @return {number}\n */\nexport default function switchSign(number) {\n  return ~number + 1;\n}\n"
  },
  {
    "path": "src/algorithms/math/bits/updateBit.js",
    "content": "/**\n * @param {number} number\n * @param {number} bitPosition - zero based.\n * @param {number} bitValue - 0 or 1.\n * @return {number}\n */\nexport default function updateBit(number, bitPosition, bitValue) {\n  // Normalized bit value.\n  const bitValueNormalized = bitValue ? 1 : 0;\n\n  // Init clear mask.\n  const clearMask = ~(1 << bitPosition);\n\n  // Clear bit value and then set it up to required value.\n  return (number & clearMask) | (bitValueNormalized << bitPosition);\n}\n"
  },
  {
    "path": "src/algorithms/math/complex-number/ComplexNumber.js",
    "content": "import radianToDegree from '../radian/radianToDegree';\n\nexport default class ComplexNumber {\n  /**\n   * z = re + im * i\n   * z = radius * e^(i * phase)\n   *\n   * @param {number} [re]\n   * @param {number} [im]\n   */\n  constructor({ re = 0, im = 0 } = {}) {\n    this.re = re;\n    this.im = im;\n  }\n\n  /**\n   * @param {ComplexNumber|number} addend\n   * @return {ComplexNumber}\n   */\n  add(addend) {\n    // Make sure we're dealing with complex number.\n    const complexAddend = this.toComplexNumber(addend);\n\n    return new ComplexNumber({\n      re: this.re + complexAddend.re,\n      im: this.im + complexAddend.im,\n    });\n  }\n\n  /**\n   * @param {ComplexNumber|number} subtrahend\n   * @return {ComplexNumber}\n   */\n  subtract(subtrahend) {\n    // Make sure we're dealing with complex number.\n    const complexSubtrahend = this.toComplexNumber(subtrahend);\n\n    return new ComplexNumber({\n      re: this.re - complexSubtrahend.re,\n      im: this.im - complexSubtrahend.im,\n    });\n  }\n\n  /**\n   * @param {ComplexNumber|number} multiplicand\n   * @return {ComplexNumber}\n   */\n  multiply(multiplicand) {\n    // Make sure we're dealing with complex number.\n    const complexMultiplicand = this.toComplexNumber(multiplicand);\n\n    return new ComplexNumber({\n      re: this.re * complexMultiplicand.re - this.im * complexMultiplicand.im,\n      im: this.re * complexMultiplicand.im + this.im * complexMultiplicand.re,\n    });\n  }\n\n  /**\n   * @param {ComplexNumber|number} divider\n   * @return {ComplexNumber}\n   */\n  divide(divider) {\n    // Make sure we're dealing with complex number.\n    const complexDivider = this.toComplexNumber(divider);\n\n    // Get divider conjugate.\n    const dividerConjugate = this.conjugate(complexDivider);\n\n    // Multiply dividend by divider's conjugate.\n    const finalDivident = this.multiply(dividerConjugate);\n\n    // Calculating final divider using formula (a + bi)(a − bi) = a^2 + b^2\n    const finalDivider = (complexDivider.re ** 2) + (complexDivider.im ** 2);\n\n    return new ComplexNumber({\n      re: finalDivident.re / finalDivider,\n      im: finalDivident.im / finalDivider,\n    });\n  }\n\n  /**\n   * @param {ComplexNumber|number} number\n   */\n  conjugate(number) {\n    // Make sure we're dealing with complex number.\n    const complexNumber = this.toComplexNumber(number);\n\n    return new ComplexNumber({\n      re: complexNumber.re,\n      im: -1 * complexNumber.im,\n    });\n  }\n\n  /**\n   * @return {number}\n   */\n  getRadius() {\n    return Math.sqrt((this.re ** 2) + (this.im ** 2));\n  }\n\n  /**\n   * @param {boolean} [inRadians]\n   * @return {number}\n   */\n  getPhase(inRadians = true) {\n    let phase = Math.atan(Math.abs(this.im) / Math.abs(this.re));\n\n    if (this.re < 0 && this.im > 0) {\n      phase = Math.PI - phase;\n    } else if (this.re < 0 && this.im < 0) {\n      phase = -(Math.PI - phase);\n    } else if (this.re > 0 && this.im < 0) {\n      phase = -phase;\n    } else if (this.re === 0 && this.im > 0) {\n      phase = Math.PI / 2;\n    } else if (this.re === 0 && this.im < 0) {\n      phase = -Math.PI / 2;\n    } else if (this.re < 0 && this.im === 0) {\n      phase = Math.PI;\n    } else if (this.re > 0 && this.im === 0) {\n      phase = 0;\n    } else if (this.re === 0 && this.im === 0) {\n      // More correctly would be to set 'indeterminate'.\n      // But just for simplicity reasons let's set zero.\n      phase = 0;\n    }\n\n    if (!inRadians) {\n      phase = radianToDegree(phase);\n    }\n\n    return phase;\n  }\n\n  /**\n   * @param {boolean} [inRadians]\n   * @return {{radius: number, phase: number}}\n   */\n  getPolarForm(inRadians = true) {\n    return {\n      radius: this.getRadius(),\n      phase: this.getPhase(inRadians),\n    };\n  }\n\n  /**\n   * Convert real numbers to complex number.\n   * In case if complex number is provided then lefts it as is.\n   *\n   * @param {ComplexNumber|number} number\n   * @return {ComplexNumber}\n   */\n  toComplexNumber(number) {\n    if (number instanceof ComplexNumber) {\n      return number;\n    }\n\n    return new ComplexNumber({ re: number });\n  }\n}\n"
  },
  {
    "path": "src/algorithms/math/complex-number/README.fr-FR.md",
    "content": "# Nombre complexe\n\n_Read this in other languages:_\n[english](README.md).\n\nUn **nombre complexe** est un nombre qui peut s'écrire sous la forme\n`a + b * i`, tels que `a` et `b` sont des nombres réels,\net `i` est la solution de l'équation `x^2 = −1`.\nDu fait qu'aucun _nombre réel_ ne statisfait l'équation,\n`i` est appellé _nombre imaginaire_. Étant donné le nombre complexe `a + b * i`,\n`a` est appellé _partie réelle_, et `b`, _partie imaginaire_.\n\n![Complex Number](https://www.mathsisfun.com/numbers/images/complex-example.svg)\n\nUn nombre complexe est donc la combinaison\nd'un nombre réel et d'un nombre imaginaire :\n\n![Complex Number](https://www.mathsisfun.com/numbers/images/complex-number.svg)\n\nEn géométrie, les nombres complexes étendent le concept\nde ligne de nombres sur une dimension à un _plan complexe à deux dimensions_\nen utilisant l'axe horizontal pour lepartie réelle\net l'axe vertical pour la partie imaginaire. Le nombre complexe `a + b * i`\npeut être identifié avec le point `(a, b)` dans le plan complexe.\n\nUn nombre complexe dont la partie réelle est zéro est dit _imaginaire pur_;\nles points pour ces nombres se trouvent sur l'axe vertical du plan complexe.\nUn nombre complexe dont la partie imaginaire est zéro\npeut être considéré comme un _nombre réel_; son point\nse trouve sur l'axe horizontal du plan complexe.\n\n| Nombre complexe | Partie réelle | partie imaginaire |                  |\n| :-------------- | :-----------: | :---------------: | ---------------- |\n| 3 + 2i          |       3       |         2         |                  |\n| 5               |       5       |       **0**       | Purely Real      |\n| −6i             |     **0**     |        -6         | Purely Imaginary |\n\nA complex number can be visually represented as a pair of numbers `(a, b)` forming\na vector on a diagram called an _Argand diagram_, representing the _complex plane_.\n`Re` is the real axis, `Im` is the imaginary axis, and `i` satisfies `i^2 = −1`.\n\nUn nombre complexe peut être représenté visuellement comme une paire de nombres\n`(a, b)` formant un vecteur sur un diagramme appelé _diagramme d'Argand_,\nreprésentant le _plan complexe_.\n_Re_ est l'axe réel, _Im_ est l'axe imaginaire et `i` satisfait `i^2 = −1`.\n\n![Complex Number](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg)\n\n> Complexe ne veut pas dire compliqué. Cela signifie simplement que\n> les deux types de nombres, réels et imaginaires, forment ensemble un complexe\n> comme on le dirait d'un complexe de bâtiments (bâtiments réunis).\n\n## Forme polaire\n\nUne manière de définir un point `P` dans le plan complexe, autre que d'utiliser\nles coordonnées x et y, consiste à utiliser la distance entre le point `O`, le point\ndont les coordonnées sont `(0, 0)` (l'origine), et l'angle sous-tendu\nentre l'axe réel positif et le segment de droite `OP` dans le sens antihoraire.\nCette idée conduit à la forme polaire des nombres complexes.\n\n![Polar Form](https://upload.wikimedia.org/wikipedia/commons/7/7a/Complex_number_illustration_modarg.svg)\n\nThe _valeur absolue_ (ou module) d'un nombre complexe `z = x + yi` est:\n\n![Radius](https://wikimedia.org/api/rest_v1/media/math/render/svg/b59629c801aa0ddcdf17ee489e028fb9f8d4ea75)\n\nL'argument de `z` (parfois appelé « phase » ou « amplitude ») est l'angle\ndu rayon `OP` avec l'axe des réels positifs, et s'écrit `arg(z)`. Comme\navec le module, l'argument peut être trouvé à partir de la forme rectangulaire `x + yi`:\n\n![Phase](https://wikimedia.org/api/rest_v1/media/math/render/svg/7cbbdd9bb1dd5df86dd2b820b20f82995023e566)\n\nEnsemble, `r` et`φ` donnent une autre façon de représenter les nombres complexes, la\nforme polaire, car la combinaison du module et de l'argument suffit à indiquer la\nposition d'un point sur le plan. Obtenir les coordonnées du rectangle d'origine\nà partir de la forme polaire se fait par la formule appelée forme trigonométrique :\n\n![Polar Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/b03de1e1b7b049880b5e4870b68a57bc180ff6ce)\n\nEn utilisant la formule d'Euler, cela peut être écrit comme suit:\n\n![Euler's Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/0a087c772212e7375cb321d83fc1fcc715cd0ed2)\n\n## Opérations de base\n\n### Addition\n\nPour ajouter deux nombres complexes, nous ajoutons chaque partie séparément :\n\n```text\n(a + b * i) + (c + d * i) = (a + c) + (b + d) * i\n```\n\n**Exemple**\n\n```text\n(3 + 5i) + (4 − 3i) = (3 + 4) + (5 − 3)i = 7 + 2i\n```\n\nDans un plan complexe, l'addition ressemblera à ceci:\n\n![Complex Addition](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg)\n\n### Soustraction\n\nPour soustraire deux nombres complexes, on soustrait chaque partie séparément :\n\n```text\n(a + b * i) - (c + d * i) = (a - c) + (b - d) * i\n```\n\n**Exemple**\n\n```text\n(3 + 5i) - (4 − 3i) = (3 - 4) + (5 + 3)i = -1 + 8i\n```\n\n### Multiplication\n\nPour multiplier les nombres complexes, chaque partie du premier nombre complexe est multipliée\npar chaque partie du deuxième nombre complexe:\n\nOn peut utiliser le \"FOIL\" (parfois traduit PEID en français), acronyme de\n**F**irsts (Premiers), **O**uters (Extérieurs), **I**nners (Intérieurs), **L**asts (Derniers)\" (\nvoir [Binomial Multiplication](ttps://www.mathsisfun.com/algebra/polynomials-multiplying.html) pour plus de détails):\n\n![Complex Multiplication](https://www.mathsisfun.com/algebra/images/foil-complex.svg)\n\n- Firsts: `a × c`\n- Outers: `a × di`\n- Inners: `bi × c`\n- Lasts: `bi × di`\n\nEn général, cela ressemble à:\n\n```text\n(a + bi)(c + di) = ac + adi + bci + bdi^2\n```\n\nMais il existe aussi un moyen plus rapide !\n\nUtiliser cette loi:\n\n```text\n(a + bi)(c + di) = (ac − bd) + (ad + bc)i\n```\n\n**Exemple**\n\n```text\n(3 + 2i)(1 + 7i)\n= 3×1 + 3×7i + 2i×1+ 2i×7i\n= 3 + 21i + 2i + 14i^2\n= 3 + 21i + 2i − 14   (because i^2 = −1)\n= −11 + 23i\n```\n\n```text\n(3 + 2i)(1 + 7i) = (3×1 − 2×7) + (3×7 + 2×1)i = −11 + 23i\n```\n\n### Conjugués\n\nEn mathématiques, le conjugué d'un nombre complexe z\nest le nombre complexe formé de la même partie réelle que z\nmais de partie imaginaire opposée.\n\nUn conjugué vois son signe changer au milieu comme suit:\n\n![Complex Conjugate](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg)\n\nUn conjugué est souvent écrit avec un trait suscrit (barre au-dessus):\n\n```text\n______\n5 − 3i   =   5 + 3i\n```\n\nDans un plan complexe, le nombre conjugué sera mirroir par rapport aux axes réels.\n\n![Complex Conjugate](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg)\n\n### Division\n\nLe conjugué est utiliser pour aider à la division de nombres complexes\n\nL'astuce est de _multiplier le haut et le bas par le conjugué du bas_.\n\n**Exemple**\n\n```text\n2 + 3i\n------\n4 − 5i\n```\n\nMultiplier le haut et le bas par le conjugué de `4 − 5i`:\n\n```text\n  (2 + 3i) * (4 + 5i)   8 + 10i + 12i + 15i^2\n= ------------------- = ----------------------\n  (4 − 5i) * (4 + 5i)   16 + 20i − 20i − 25i^2\n```\n\nEt puisque `i^2 = −1`, il s'ensuit que:\n\n```text\n  8 + 10i + 12i − 15    −7 + 22i   −7   22\n= ------------------- = -------- = -- + -- * i\n  16 + 20i − 20i + 25      41      41   41\n\n```\n\nIl existe cependant un moyen plus direct.\n\nDans l'exemple précédent, ce qui s'est passé en bas était intéressant:\n\n```text\n(4 − 5i)(4 + 5i) = 16 + 20i − 20i − 25i\n```\n\nLes termes du milieu `(20i − 20i)` s'annule! Et pusique `i^2 = −1` on retrouve:\n\n```text\n(4 − 5i)(4 + 5i) = 4^2 + 5^2\n```\n\nCe qui est vraiment un résultat assez simple. La règle générale est:\n\n```text\n(a + bi)(a − bi) = a^2 + b^2\n```\n\n## Références\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/Nombre_complexe)\n- [Math is Fun](https://www.mathsisfun.com/numbers/complex-numbers.html)\n"
  },
  {
    "path": "src/algorithms/math/complex-number/README.md",
    "content": "# Complex Number\n\n_Read this in other languages:_\n[français](README.fr-FR.md).\n\nA **complex number** is a number that can be expressed in the\nform `a + b * i`, where `a` and `b` are real numbers, and `i` is a solution of\nthe equation `x^2 = −1`. Because no _real number_ satisfies this\nequation, `i` is called an _imaginary number_. For the complex\nnumber `a + b * i`, `a` is called the _real part_, and `b` is called\nthe _imaginary part_.\n\n![Complex Number](https://www.mathsisfun.com/numbers/images/complex-example.svg)\n\nA Complex Number is a combination of a Real Number and an Imaginary Number:\n\n![Complex Number](https://www.mathsisfun.com/numbers/images/complex-number.svg)\n\nGeometrically, complex numbers extend the concept of the one-dimensional number\nline to the _two-dimensional complex plane_ by using the horizontal axis for the\nreal part and the vertical axis for the imaginary part. The complex\nnumber `a + b * i` can be identified with the point `(a, b)` in the complex plane.\n\nA complex number whose real part is zero is said to be _purely imaginary_; the\npoints for these numbers lie on the vertical axis of the complex plane. A complex\nnumber whose imaginary part is zero can be viewed as a _real number_; its point\nlies on the horizontal axis of the complex plane.\n\n| Complex Number | Real Part | Imaginary Part |                  |\n| :------------- | :-------: | :------------: | ---------------- |\n| 3 + 2i         |     3     |       2        |                  |\n| 5              |     5     |     **0**      | Purely Real      |\n| −6i            |   **0**   |       -6       | Purely Imaginary |\n\nA complex number can be visually represented as a pair of numbers `(a, b)` forming\na vector on a diagram called an _Argand diagram_, representing the _complex plane_.\n`Re` is the real axis, `Im` is the imaginary axis, and `i` satisfies `i^2 = −1`.\n\n![Complex Number](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg)\n\n> Complex does not mean complicated. It means the two types of numbers, real and\n> imaginary, together form a complex, just like a building complex (buildings\n> joined together).\n\n## Polar Form\n\nAn alternative way of defining a point `P` in the complex plane, other than using\nthe x- and y-coordinates, is to use the distance of the point from `O`, the point\nwhose coordinates are `(0, 0)` (the origin), together with the angle subtended\nbetween the positive real axis and the line segment `OP` in a counterclockwise\ndirection. This idea leads to the polar form of complex numbers.\n\n![Polar Form](https://upload.wikimedia.org/wikipedia/commons/7/7a/Complex_number_illustration_modarg.svg)\n\nThe _absolute value_ (or modulus or magnitude) of a complex number `z = x + yi` is:\n\n![Radius](https://wikimedia.org/api/rest_v1/media/math/render/svg/b59629c801aa0ddcdf17ee489e028fb9f8d4ea75)\n\nThe argument of `z` (in many applications referred to as the \"phase\") is the angle\nof the radius `OP` with the positive real axis, and is written as `arg(z)`. As\nwith the modulus, the argument can be found from the rectangular form `x+yi`:\n\n![Phase](https://wikimedia.org/api/rest_v1/media/math/render/svg/7cbbdd9bb1dd5df86dd2b820b20f82995023e566)\n\nTogether, `r` and `φ` give another way of representing complex numbers, the\npolar form, as the combination of modulus and argument fully specify the\nposition of a point on the plane. Recovering the original rectangular\nco-ordinates from the polar form is done by the formula called trigonometric\nform:\n\n![Polar Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/b03de1e1b7b049880b5e4870b68a57bc180ff6ce)\n\nUsing Euler's formula this can be written as:\n\n![Euler's Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/0a087c772212e7375cb321d83fc1fcc715cd0ed2)\n\n## Basic Operations\n\n### Adding\n\nTo add two complex numbers we add each part separately:\n\n```text\n(a + b * i) + (c + d * i) = (a + c) + (b + d) * i\n```\n\n**Example**\n\n```text\n(3 + 5i) + (4 − 3i) = (3 + 4) + (5 − 3)i = 7 + 2i\n```\n\nOn complex plane the adding operation will look like the following:\n\n![Complex Addition](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg)\n\n### Subtracting\n\nTo subtract two complex numbers we subtract each part separately:\n\n```text\n(a + b * i) - (c + d * i) = (a - c) + (b - d) * i\n```\n\n**Example**\n\n```text\n(3 + 5i) - (4 − 3i) = (3 - 4) + (5 + 3)i = -1 + 8i\n```\n\n### Multiplying\n\nTo multiply complex numbers each part of the first complex number gets multiplied\nby each part of the second complex number:\n\nJust use \"FOIL\", which stands for \"**F**irsts, **O**uters, **I**nners, **L**asts\" (\nsee [Binomial Multiplication](ttps://www.mathsisfun.com/algebra/polynomials-multiplying.html) for\nmore details):\n\n![Complex Multiplication](https://www.mathsisfun.com/algebra/images/foil-complex.svg)\n\n- Firsts: `a × c`\n- Outers: `a × di`\n- Inners: `bi × c`\n- Lasts: `bi × di`\n\nIn general it looks like this:\n\n```text\n(a + bi)(c + di) = ac + adi + bci + bdi^2\n```\n\nBut there is also a quicker way!\n\nUse this rule:\n\n```text\n(a + bi)(c + di) = (ac − bd) + (ad + bc)i\n```\n\n**Example**\n\n```text\n(3 + 2i)(1 + 7i)\n= 3×1 + 3×7i + 2i×1+ 2i×7i\n= 3 + 21i + 2i + 14i^2\n= 3 + 21i + 2i − 14   (because i^2 = −1)\n= −11 + 23i\n```\n\n```text\n(3 + 2i)(1 + 7i) = (3×1 − 2×7) + (3×7 + 2×1)i = −11 + 23i\n```\n\n### Conjugates\n\nWe will need to know about conjugates in a minute!\n\nA conjugate is where we change the sign in the middle like this:\n\n![Complex Conjugate](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg)\n\nA conjugate is often written with a bar over it:\n\n```text\n______\n5 − 3i   =   5 + 3i\n```\n\nOn the complex plane the conjugate number will be mirrored against real axes.\n\n![Complex Conjugate](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg)\n\n### Dividing\n\nThe conjugate is used to help complex division.\n\nThe trick is to _multiply both top and bottom by the conjugate of the bottom_.\n\n**Example**\n\n```text\n2 + 3i\n------\n4 − 5i\n```\n\nMultiply top and bottom by the conjugate of `4 − 5i`:\n\n```text\n  (2 + 3i) * (4 + 5i)   8 + 10i + 12i + 15i^2\n= ------------------- = ----------------------\n  (4 − 5i) * (4 + 5i)   16 + 20i − 20i − 25i^2\n```\n\nNow remember that `i^2 = −1`, so:\n\n```text\n  8 + 10i + 12i − 15    −7 + 22i   −7   22\n= ------------------- = -------- = -- + -- * i\n  16 + 20i − 20i + 25      41      41   41\n\n```\n\nThere is a faster way though.\n\nIn the previous example, what happened on the bottom was interesting:\n\n```text\n(4 − 5i)(4 + 5i) = 16 + 20i − 20i − 25i\n```\n\nThe middle terms `(20i − 20i)` cancel out! Also `i^2 = −1` so we end up with this:\n\n```text\n(4 − 5i)(4 + 5i) = 4^2 + 5^2\n```\n\nWhich is really quite a simple result. The general rule is:\n\n```text\n(a + bi)(a − bi) = a^2 + b^2\n```\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Complex_number)\n- [Math is Fun](https://www.mathsisfun.com/numbers/complex-numbers.html)\n"
  },
  {
    "path": "src/algorithms/math/complex-number/__test__/ComplexNumber.test.js",
    "content": "import ComplexNumber from '../ComplexNumber';\n\ndescribe('ComplexNumber', () => {\n  it('should create complex numbers', () => {\n    const complexNumber = new ComplexNumber({ re: 1, im: 2 });\n\n    expect(complexNumber).toBeDefined();\n    expect(complexNumber.re).toBe(1);\n    expect(complexNumber.im).toBe(2);\n\n    const defaultComplexNumber = new ComplexNumber();\n    expect(defaultComplexNumber.re).toBe(0);\n    expect(defaultComplexNumber.im).toBe(0);\n  });\n\n  it('should add complex numbers', () => {\n    const complexNumber1 = new ComplexNumber({ re: 1, im: 2 });\n    const complexNumber2 = new ComplexNumber({ re: 3, im: 8 });\n\n    const complexNumber3 = complexNumber1.add(complexNumber2);\n    const complexNumber4 = complexNumber2.add(complexNumber1);\n\n    expect(complexNumber3.re).toBe(1 + 3);\n    expect(complexNumber3.im).toBe(2 + 8);\n\n    expect(complexNumber4.re).toBe(1 + 3);\n    expect(complexNumber4.im).toBe(2 + 8);\n  });\n\n  it('should add complex and natural numbers', () => {\n    const complexNumber = new ComplexNumber({ re: 1, im: 2 });\n    const realNumber = new ComplexNumber({ re: 3 });\n\n    const complexNumber3 = complexNumber.add(realNumber);\n    const complexNumber4 = realNumber.add(complexNumber);\n    const complexNumber5 = complexNumber.add(3);\n\n    expect(complexNumber3.re).toBe(1 + 3);\n    expect(complexNumber3.im).toBe(2);\n\n    expect(complexNumber4.re).toBe(1 + 3);\n    expect(complexNumber4.im).toBe(2);\n\n    expect(complexNumber5.re).toBe(1 + 3);\n    expect(complexNumber5.im).toBe(2);\n  });\n\n  it('should subtract complex numbers', () => {\n    const complexNumber1 = new ComplexNumber({ re: 1, im: 2 });\n    const complexNumber2 = new ComplexNumber({ re: 3, im: 8 });\n\n    const complexNumber3 = complexNumber1.subtract(complexNumber2);\n    const complexNumber4 = complexNumber2.subtract(complexNumber1);\n\n    expect(complexNumber3.re).toBe(1 - 3);\n    expect(complexNumber3.im).toBe(2 - 8);\n\n    expect(complexNumber4.re).toBe(3 - 1);\n    expect(complexNumber4.im).toBe(8 - 2);\n  });\n\n  it('should subtract complex and natural numbers', () => {\n    const complexNumber = new ComplexNumber({ re: 1, im: 2 });\n    const realNumber = new ComplexNumber({ re: 3 });\n\n    const complexNumber3 = complexNumber.subtract(realNumber);\n    const complexNumber4 = realNumber.subtract(complexNumber);\n    const complexNumber5 = complexNumber.subtract(3);\n\n    expect(complexNumber3.re).toBe(1 - 3);\n    expect(complexNumber3.im).toBe(2);\n\n    expect(complexNumber4.re).toBe(3 - 1);\n    expect(complexNumber4.im).toBe(-2);\n\n    expect(complexNumber5.re).toBe(1 - 3);\n    expect(complexNumber5.im).toBe(2);\n  });\n\n  it('should multiply complex numbers', () => {\n    const complexNumber1 = new ComplexNumber({ re: 3, im: 2 });\n    const complexNumber2 = new ComplexNumber({ re: 1, im: 7 });\n\n    const complexNumber3 = complexNumber1.multiply(complexNumber2);\n    const complexNumber4 = complexNumber2.multiply(complexNumber1);\n    const complexNumber5 = complexNumber1.multiply(5);\n\n    expect(complexNumber3.re).toBe(-11);\n    expect(complexNumber3.im).toBe(23);\n\n    expect(complexNumber4.re).toBe(-11);\n    expect(complexNumber4.im).toBe(23);\n\n    expect(complexNumber5.re).toBe(15);\n    expect(complexNumber5.im).toBe(10);\n  });\n\n  it('should multiply complex numbers by themselves', () => {\n    const complexNumber = new ComplexNumber({ re: 1, im: 1 });\n\n    const result = complexNumber.multiply(complexNumber);\n\n    expect(result.re).toBe(0);\n    expect(result.im).toBe(2);\n  });\n\n  it('should calculate i in power of two', () => {\n    const complexNumber = new ComplexNumber({ re: 0, im: 1 });\n\n    const result = complexNumber.multiply(complexNumber);\n\n    expect(result.re).toBe(-1);\n    expect(result.im).toBe(0);\n  });\n\n  it('should divide complex numbers', () => {\n    const complexNumber1 = new ComplexNumber({ re: 2, im: 3 });\n    const complexNumber2 = new ComplexNumber({ re: 4, im: -5 });\n\n    const complexNumber3 = complexNumber1.divide(complexNumber2);\n    const complexNumber4 = complexNumber1.divide(2);\n\n    expect(complexNumber3.re).toBe(-7 / 41);\n    expect(complexNumber3.im).toBe(22 / 41);\n\n    expect(complexNumber4.re).toBe(1);\n    expect(complexNumber4.im).toBe(1.5);\n  });\n\n  it('should return complex number in polar form', () => {\n    const complexNumber1 = new ComplexNumber({ re: 3, im: 3 });\n    expect(complexNumber1.getPolarForm().radius).toBe(Math.sqrt((3 ** 2) + (3 ** 2)));\n    expect(complexNumber1.getPolarForm().phase).toBe(Math.PI / 4);\n    expect(complexNumber1.getPolarForm(false).phase).toBe(45);\n\n    const complexNumber2 = new ComplexNumber({ re: -3, im: 3 });\n    expect(complexNumber2.getPolarForm().radius).toBe(Math.sqrt((3 ** 2) + (3 ** 2)));\n    expect(complexNumber2.getPolarForm().phase).toBe(3 * (Math.PI / 4));\n    expect(complexNumber2.getPolarForm(false).phase).toBe(135);\n\n    const complexNumber3 = new ComplexNumber({ re: -3, im: -3 });\n    expect(complexNumber3.getPolarForm().radius).toBe(Math.sqrt((3 ** 2) + (3 ** 2)));\n    expect(complexNumber3.getPolarForm().phase).toBe(-3 * (Math.PI / 4));\n    expect(complexNumber3.getPolarForm(false).phase).toBe(-135);\n\n    const complexNumber4 = new ComplexNumber({ re: 3, im: -3 });\n    expect(complexNumber4.getPolarForm().radius).toBe(Math.sqrt((3 ** 2) + (3 ** 2)));\n    expect(complexNumber4.getPolarForm().phase).toBe(-1 * (Math.PI / 4));\n    expect(complexNumber4.getPolarForm(false).phase).toBe(-45);\n\n    const complexNumber5 = new ComplexNumber({ re: 5, im: 7 });\n    expect(complexNumber5.getPolarForm().radius).toBeCloseTo(8.60);\n    expect(complexNumber5.getPolarForm().phase).toBeCloseTo(0.95);\n    expect(complexNumber5.getPolarForm(false).phase).toBeCloseTo(54.46);\n\n    const complexNumber6 = new ComplexNumber({ re: 0, im: 0.25 });\n    expect(complexNumber6.getPolarForm().radius).toBeCloseTo(0.25);\n    expect(complexNumber6.getPolarForm().phase).toBeCloseTo(1.57);\n    expect(complexNumber6.getPolarForm(false).phase).toBeCloseTo(90);\n\n    const complexNumber7 = new ComplexNumber({ re: 0, im: -0.25 });\n    expect(complexNumber7.getPolarForm().radius).toBeCloseTo(0.25);\n    expect(complexNumber7.getPolarForm().phase).toBeCloseTo(-1.57);\n    expect(complexNumber7.getPolarForm(false).phase).toBeCloseTo(-90);\n\n    const complexNumber8 = new ComplexNumber();\n    expect(complexNumber8.getPolarForm().radius).toBeCloseTo(0);\n    expect(complexNumber8.getPolarForm().phase).toBeCloseTo(0);\n    expect(complexNumber8.getPolarForm(false).phase).toBeCloseTo(0);\n\n    const complexNumber9 = new ComplexNumber({ re: -0.25, im: 0 });\n    expect(complexNumber9.getPolarForm().radius).toBeCloseTo(0.25);\n    expect(complexNumber9.getPolarForm().phase).toBeCloseTo(Math.PI);\n    expect(complexNumber9.getPolarForm(false).phase).toBeCloseTo(180);\n\n    const complexNumber10 = new ComplexNumber({ re: 0.25, im: 0 });\n    expect(complexNumber10.getPolarForm().radius).toBeCloseTo(0.25);\n    expect(complexNumber10.getPolarForm().phase).toBeCloseTo(0);\n    expect(complexNumber10.getPolarForm(false).phase).toBeCloseTo(0);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/euclidean-algorithm/README.fr-FR.md",
    "content": "# Algorithme d'Euclide\n\n_Read this in other languages:_\n[english](README.md).\n\nEn 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.\n\nLe 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.\n\nEn inversant les étapes, le PGCD peut être exprimé comme une somme de\nles deux nombres originaux, chacun étant multiplié\npar un entier positif ou négatif, par exemple `21 = 5 × 105 + (-2) × 252`.\nLe fait que le PGCD puisse toujours être exprimé de cette manière est\nconnue sous le nom de Théorème de Bachet-Bézout.\n\n![GCD](https://upload.wikimedia.org/wikipedia/commons/3/37/Euclid%27s_algorithm_Book_VII_Proposition_2_3.png)\n\nLa Méthode d'Euclide pour trouver le plus grand diviseur commun (PGCD)\nde deux longueurs de départ`BA` et `DC`, toutes deux définies comme étant\nmultiples d'une longueur commune. La longueur `DC` étant\nplus courte, elle est utilisée pour « mesurer » `BA`, mais une seule fois car\nle reste `EA` est inférieur à `DC`. `EA` mesure maintenant (deux fois)\nla longueur la plus courte `DC`, le reste `FC` étant plus court que `EA`.\nAlors `FC` mesure (trois fois) la longueur `EA`. Parce qu'il y a\npas de reste, le processus se termine par `FC` étant le « PGCD ».\nÀ droite, l'exemple de Nicomaque de Gérase avec les nombres `49` et `21`\nayan un PGCD de `7` (dérivé de Heath 1908: 300).\n\n![GCD](https://upload.wikimedia.org/wikipedia/commons/7/74/24x60.svg)\n\nUn de rectangle de dimensions `24 par 60` peux se carreler en carrés de `12 par 12`,\npuisque `12` est le PGCD ed `24` et `60`. De façon générale,\nun rectangle de dimension `a par b` peut se carreler en carrés\nde côté `c`, seulement si `c` est un diviseur commun de `a` et `b`.\n\n![GCD](https://upload.wikimedia.org/wikipedia/commons/1/1c/Euclidean_algorithm_1071_462.gif)\n\nAnimation basée sur la soustraction via l'algorithme euclidien.\nLe rectangle initial a les dimensions `a = 1071` et `b = 462`.\nDes carrés de taille `462 × 462` y sont placés en laissant un\nrectangle de `462 × 147`. Ce rectangle est carrelé avec des\ncarrés de `147 × 147` jusqu'à ce qu'un rectangle de `21 × 147` soit laissé,\nqui à son tour estcarrelé avec des carrés `21 × 21`,\nne laissant aucune zone non couverte.\nLa plus petite taille carrée, `21`, est le PGCD de `1071` et `462`.\n\n## References\n\n[Wikipedia](https://fr.wikipedia.org/wiki/Algorithme_d%27Euclide)\n"
  },
  {
    "path": "src/algorithms/math/euclidean-algorithm/README.md",
    "content": "# Euclidean algorithm\n\n_Read this in other languages:_\n[français](README.fr-FR.md).\n\nIn mathematics, the Euclidean algorithm, or Euclid's algorithm,\nis an efficient method for computing the greatest common divisor\n(GCD) of two numbers, the largest number that divides both of\nthem without leaving a remainder.\n\nThe Euclidean algorithm is based on the principle that the\ngreatest common divisor of two numbers does not change if\nthe larger number is replaced by its difference with the\nsmaller number. For example, `21` is the GCD of `252` and\n`105` (as `252 = 21 × 12` and `105 = 21 × 5`), and the same\nnumber `21` is also the GCD of `105` and `252 − 105 = 147`.\nSince this replacement reduces the larger of the two numbers,\nrepeating this process gives successively smaller pairs of\nnumbers until the two numbers become equal.\nWhen that occurs, they are the GCD of the original two numbers.\n\nBy reversing the steps, the GCD can be expressed as a sum of\nthe two original numbers each multiplied by a positive or\nnegative integer, e.g., `21 = 5 × 105 + (−2) × 252`.\nThe fact that the GCD can always be expressed in this way is\nknown as Bézout's identity.\n\n![GCD](https://upload.wikimedia.org/wikipedia/commons/3/37/Euclid%27s_algorithm_Book_VII_Proposition_2_3.png)\n\nEuclid's method for finding the greatest common divisor (GCD)\nof two starting lengths `BA` and `DC`, both defined to be\nmultiples of a common \"unit\" length. The length `DC` being\nshorter, it is used to \"measure\" `BA`, but only once because\nremainder `EA` is less than `DC`. EA now measures (twice)\nthe shorter length `DC`, with remainder `FC` shorter than `EA`.\nThen `FC` measures (three times) length `EA`. Because there is\nno remainder, the process ends with `FC` being the `GCD`.\nOn the right Nicomachus' example with numbers `49` and `21`\nresulting in their GCD of `7` (derived from Heath 1908:300).\n\n![GCD](https://upload.wikimedia.org/wikipedia/commons/7/74/24x60.svg)\n\nA `24-by-60` rectangle is covered with ten `12-by-12` square\ntiles, where `12` is the GCD of `24` and `60`. More generally,\nan `a-by-b` rectangle can be covered with square tiles of\nside-length `c` only if `c` is a common divisor of `a` and `b`.\n\n![GCD](https://upload.wikimedia.org/wikipedia/commons/1/1c/Euclidean_algorithm_1071_462.gif)\n\nSubtraction-based animation of the Euclidean algorithm.\nThe initial rectangle has dimensions `a = 1071` and `b = 462`.\nSquares of size `462×462` are placed within it leaving a\n`462×147` rectangle. This rectangle is tiled with `147×147`\nsquares until a `21×147` rectangle is left, which in turn is\ntiled with `21×21` squares, leaving no uncovered area.\nThe smallest square size, `21`, is the GCD of `1071` and `462`.\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Euclidean_algorithm)\n"
  },
  {
    "path": "src/algorithms/math/euclidean-algorithm/__test__/euclideanAlgorithm.test.js",
    "content": "import euclideanAlgorithm from '../euclideanAlgorithm';\n\ndescribe('euclideanAlgorithm', () => {\n  it('should calculate GCD recursively', () => {\n    expect(euclideanAlgorithm(0, 0)).toBe(0);\n    expect(euclideanAlgorithm(2, 0)).toBe(2);\n    expect(euclideanAlgorithm(0, 2)).toBe(2);\n    expect(euclideanAlgorithm(1, 2)).toBe(1);\n    expect(euclideanAlgorithm(2, 1)).toBe(1);\n    expect(euclideanAlgorithm(6, 6)).toBe(6);\n    expect(euclideanAlgorithm(2, 4)).toBe(2);\n    expect(euclideanAlgorithm(4, 2)).toBe(2);\n    expect(euclideanAlgorithm(12, 4)).toBe(4);\n    expect(euclideanAlgorithm(4, 12)).toBe(4);\n    expect(euclideanAlgorithm(5, 13)).toBe(1);\n    expect(euclideanAlgorithm(27, 13)).toBe(1);\n    expect(euclideanAlgorithm(24, 60)).toBe(12);\n    expect(euclideanAlgorithm(60, 24)).toBe(12);\n    expect(euclideanAlgorithm(252, 105)).toBe(21);\n    expect(euclideanAlgorithm(105, 252)).toBe(21);\n    expect(euclideanAlgorithm(1071, 462)).toBe(21);\n    expect(euclideanAlgorithm(462, 1071)).toBe(21);\n    expect(euclideanAlgorithm(462, -1071)).toBe(21);\n    expect(euclideanAlgorithm(-462, -1071)).toBe(21);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/euclidean-algorithm/__test__/euclideanAlgorithmIterative.test.js",
    "content": "import euclideanAlgorithmIterative from '../euclideanAlgorithmIterative';\n\ndescribe('euclideanAlgorithmIterative', () => {\n  it('should calculate GCD iteratively', () => {\n    expect(euclideanAlgorithmIterative(0, 0)).toBe(0);\n    expect(euclideanAlgorithmIterative(2, 0)).toBe(2);\n    expect(euclideanAlgorithmIterative(0, 2)).toBe(2);\n    expect(euclideanAlgorithmIterative(1, 2)).toBe(1);\n    expect(euclideanAlgorithmIterative(2, 1)).toBe(1);\n    expect(euclideanAlgorithmIterative(6, 6)).toBe(6);\n    expect(euclideanAlgorithmIterative(2, 4)).toBe(2);\n    expect(euclideanAlgorithmIterative(4, 2)).toBe(2);\n    expect(euclideanAlgorithmIterative(12, 4)).toBe(4);\n    expect(euclideanAlgorithmIterative(4, 12)).toBe(4);\n    expect(euclideanAlgorithmIterative(5, 13)).toBe(1);\n    expect(euclideanAlgorithmIterative(27, 13)).toBe(1);\n    expect(euclideanAlgorithmIterative(24, 60)).toBe(12);\n    expect(euclideanAlgorithmIterative(60, 24)).toBe(12);\n    expect(euclideanAlgorithmIterative(252, 105)).toBe(21);\n    expect(euclideanAlgorithmIterative(105, 252)).toBe(21);\n    expect(euclideanAlgorithmIterative(1071, 462)).toBe(21);\n    expect(euclideanAlgorithmIterative(462, 1071)).toBe(21);\n    expect(euclideanAlgorithmIterative(462, -1071)).toBe(21);\n    expect(euclideanAlgorithmIterative(-462, -1071)).toBe(21);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/euclidean-algorithm/euclideanAlgorithm.js",
    "content": "/**\n * Recursive version of Euclidean Algorithm of finding greatest common divisor (GCD).\n * @param {number} originalA\n * @param {number} originalB\n * @return {number}\n */\nexport default function euclideanAlgorithm(originalA, originalB) {\n  // Make input numbers positive.\n  const a = Math.abs(originalA);\n  const b = Math.abs(originalB);\n\n  // To make algorithm work faster instead of subtracting one number from the other\n  // we may use modulo operation.\n  return (b === 0) ? a : euclideanAlgorithm(b, a % b);\n}\n"
  },
  {
    "path": "src/algorithms/math/euclidean-algorithm/euclideanAlgorithmIterative.js",
    "content": "/**\n * Iterative version of Euclidean Algorithm of finding greatest common divisor (GCD).\n * @param {number} originalA\n * @param {number} originalB\n * @return {number}\n */\nexport default function euclideanAlgorithmIterative(originalA, originalB) {\n  // Make input numbers positive.\n  let a = Math.abs(originalA);\n  let b = Math.abs(originalB);\n\n  // Subtract one number from another until both numbers would become the same.\n  // This will be out GCD. Also quit the loop if one of the numbers is zero.\n  while (a && b && a !== b) {\n    [a, b] = a > b ? [a - b, b] : [a, b - a];\n  }\n\n  // Return the number that is not equal to zero since the last subtraction (it will be a GCD).\n  return a || b;\n}\n"
  },
  {
    "path": "src/algorithms/math/euclidean-distance/README.md",
    "content": "# Euclidean Distance\n\nIn 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.\n\n![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)\n\n## Distance formulas\n\n### One dimension\n\nThe distance between any two points on the real line is the absolute value of the numerical difference of their coordinates\n\n![One dimension formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/7d75418dbec9482dbcb70f9063ad66e9cf7b5db9)\n\n### Two dimensions\n\n![Two dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/9c0157084fd89f5f3d462efeedc47d3d7aa0b773)\n\n### Higher dimensions\n\nIn three dimensions, for points given by their Cartesian coordinates, the distance is\n\n![Three dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1d13a40a7b203b455ae6d4be8b3cce898bda625)\n\nExample: the distance between the two points `(8,2,6)` and `(3,5,7)`:\n\n![3-dimension example](https://www.mathsisfun.com/algebra/images/dist-2-points-3d.svg)\n\nIn general, for points given by Cartesian coordinates in `n`-dimensional Euclidean space, the distance is\n\n![n-dimensional formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0ef4fe055b2a51b4cca43a05e5d1cd93f758dcc)\n\n## References\n\n- [Euclidean Distance on MathIsFun](https://www.mathsisfun.com/algebra/distance-2-points.html)\n- [Euclidean Distance on Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)\n"
  },
  {
    "path": "src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js",
    "content": "import euclideanDistance from '../euclideanDistance';\n\ndescribe('euclideanDistance', () => {\n  it('should calculate euclidean distance between vectors', () => {\n    expect(euclideanDistance([[1]], [[2]])).toEqual(1);\n    expect(euclideanDistance([[2]], [[1]])).toEqual(1);\n    expect(euclideanDistance([[5, 8]], [[7, 3]])).toEqual(5.39);\n    expect(euclideanDistance([[5], [8]], [[7], [3]])).toEqual(5.39);\n    expect(euclideanDistance([[8, 2, 6]], [[3, 5, 7]])).toEqual(5.92);\n    expect(euclideanDistance([[8], [2], [6]], [[3], [5], [7]])).toEqual(5.92);\n    expect(euclideanDistance([[[8]], [[2]], [[6]]], [[[3]], [[5]], [[7]]])).toEqual(5.92);\n  });\n\n  it('should throw an error in case if two matrices are of different shapes', () => {\n    expect(() => euclideanDistance([[1]], [[[2]]])).toThrow(\n      'Matrices have different dimensions',\n    );\n\n    expect(() => euclideanDistance([[1]], [[2, 3]])).toThrow(\n      'Matrices have different shapes',\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/euclidean-distance/euclideanDistance.js",
    "content": "/**\n * @typedef {import('../matrix/Matrix.js').Matrix} Matrix\n */\n\nimport * as mtrx from '../matrix/Matrix';\n\n/**\n * Calculates the euclidean distance between 2 matrices.\n *\n * @param {Matrix} a\n * @param {Matrix} b\n * @returns {number}\n * @trows {Error}\n */\nconst euclideanDistance = (a, b) => {\n  mtrx.validateSameShape(a, b);\n\n  let squaresTotal = 0;\n\n  mtrx.walk(a, (indices, aCellValue) => {\n    const bCellValue = mtrx.getCellAtIndex(b, indices);\n    squaresTotal += (aCellValue - bCellValue) ** 2;\n  });\n\n  return Number(Math.sqrt(squaresTotal).toFixed(2));\n};\n\nexport default euclideanDistance;\n"
  },
  {
    "path": "src/algorithms/math/factorial/README.fr-FR.md",
    "content": "# Factorielle\n\n_Lisez ceci dans d'autres langues:_\n[english](README.md), [_简体中文_](README.zh-CN.md).\n\nEn mathématiques, la factorielle d'un entier naturel `n`,\nnotée avec un point d'exclamation `n!`, est le produit des nombres entiers\nstrictement positifs inférieurs ou égaux à n. Par exemple:\n\n```\n5! = 5 * 4 * 3 * 2 * 1 = 120\n```\n\n| n   |                n! |\n| --- | ----------------: |\n| 0   |                 1 |\n| 1   |                 1 |\n| 2   |                 2 |\n| 3   |                 6 |\n| 4   |                24 |\n| 5   |               120 |\n| 6   |               720 |\n| 7   |             5 040 |\n| 8   |            40 320 |\n| 9   |           362 880 |\n| 10  |         3 628 800 |\n| 11  |        39 916 800 |\n| 12  |       479 001 600 |\n| 13  |     6 227 020 800 |\n| 14  |    87 178 291 200 |\n| 15  | 1 307 674 368 000 |\n\n## References\n\n[Wikipedia](https://fr.wikipedia.org/wiki/Factorielle)\n"
  },
  {
    "path": "src/algorithms/math/factorial/README.ka-GE.md",
    "content": "# ფაქტორიალი\n\nმათემატიკაში `n` ნატურალური რიცხვის ფაქტორიალი\n(აღინიშნება `n!` სიმბოლოთი)\nარის ყველა ნატურალური რიცხვის ნამრავლი 1-იდან `n`-ის ჩათვლით. მაგალითად:\n\n```\n5! = 5 * 4 * 3 * 2 * 1 = 120\n```\n\n| n   |                n! |\n| --- | ----------------: |\n| 0   |                 1 |\n| 1   |                 1 |\n| 2   |                 2 |\n| 3   |                 6 |\n| 4   |                24 |\n| 5   |               120 |\n| 6   |               720 |\n| 7   |             5 040 |\n| 8   |            40 320 |\n| 9   |           362 880 |\n| 10  |         3 628 800 |\n| 11  |        39 916 800 |\n| 12  |       479 001 600 |\n| 13  |     6 227 020 800 |\n| 14  |    87 178 291 200 |\n| 15  | 1 307 674 368 000 |\n\n## სქოლიო\n\n[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)\n"
  },
  {
    "path": "src/algorithms/math/factorial/README.md",
    "content": "# Factorial\n\n_Read this in other languages:_\n[_简体中文_](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).\n\nIn mathematics, the factorial of a non-negative integer `n`,\ndenoted by `n!`, is the product of all positive integers less\nthan or equal to `n`. For example:\n\n```\n5! = 5 * 4 * 3 * 2 * 1 = 120\n```\n\n| n   |                n! |\n| --- | ----------------: |\n| 0   |                 1 |\n| 1   |                 1 |\n| 2   |                 2 |\n| 3   |                 6 |\n| 4   |                24 |\n| 5   |               120 |\n| 6   |               720 |\n| 7   |             5 040 |\n| 8   |            40 320 |\n| 9   |           362 880 |\n| 10  |         3 628 800 |\n| 11  |        39 916 800 |\n| 12  |       479 001 600 |\n| 13  |     6 227 020 800 |\n| 14  |    87 178 291 200 |\n| 15  | 1 307 674 368 000 |\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Factorial)\n"
  },
  {
    "path": "src/algorithms/math/factorial/README.tr-TR.md",
    "content": "# Faktöriyel\n\n_Bunu diğer dillerde okuyun:_\n[_简体中文_](README.zh-CN.md), [français](README.fr-FR.md).\n\nFaktöriyel, matematikte, sağına ünlem işareti konulmuş sayıya\nverilen isim, daha genel olan Gama fonksiyonunun tam sayılarla\nsınırlanmış özel bir durumudur. 1'den başlayarak belirli bir\nsayma sayısına kadar olan sayıların çarpımına o sayının\nfaktöriyeli denir. Basit bir şekilde faktöriyel, n tane ayrık\nelemanın kaç farklı şekilde sıralanabileceğidir.\n\n```\n5! = 5 * 4 * 3 * 2 * 1 = 120\n```\n\n| n   |                n! |\n| --- | ----------------: |\n| 0   |                 1 |\n| 1   |                 1 |\n| 2   |                 2 |\n| 3   |                 6 |\n| 4   |                24 |\n| 5   |               120 |\n| 6   |               720 |\n| 7   |             5 040 |\n| 8   |            40 320 |\n| 9   |           362 880 |\n| 10  |         3 628 800 |\n| 11  |        39 916 800 |\n| 12  |       479 001 600 |\n| 13  |     6 227 020 800 |\n| 14  |    87 178 291 200 |\n| 15  | 1 307 674 368 000 |\n\n## Referanslar\n\n[Wikipedia](https://en.wikipedia.org/wiki/Factorial)\n"
  },
  {
    "path": "src/algorithms/math/factorial/README.uk-UA.md",
    "content": "# Факторіал\n\n_Прочитайте це іншими мовами:_\n[_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`, позначений `n!`, є добутком усіх натуральних чисел, менших або рівних `n`. Наприклад:\n\n```\n5! = 5 * 4 * 3 * 2 * 1 = 120\n```\n\n| n   |                n! |\n| --- | ----------------: |\n| 0   |                 1 |\n| 1   |                 1 |\n| 2   |                 2 |\n| 3   |                 6 |\n| 4   |                24 |\n| 5   |               120 |\n| 6   |               720 |\n| 7   |             5 040 |\n| 8   |            40 320 |\n| 9   |           362 880 |\n| 10  |         3 628 800 |\n| 11  |        39 916 800 |\n| 12  |       479 001 600 |\n| 13  |     6 227 020 800 |\n| 14  |    87 178 291 200 |\n| 15  | 1 307 674 368 000 |\n\n## Посилання\n\n[Wikipedia](https://uk.wikipedia.org/wiki/%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D1%96%D0%B0%D0%BB)\n"
  },
  {
    "path": "src/algorithms/math/factorial/README.zh-CN.md",
    "content": "# 阶乘\n\n在数学上, 一个正整数 `n` 的阶乘 (写作 `n!`), 就是所有小于等于 `n` 的正整数的乘积. 比如:\n\n```\n5! = 5 * 4 * 3 * 2 * 1 = 120\n```\n\n| n     | n!                          | \n| ----- | --------------------------: |\n| 0     | 1                           |\n| 1     | 1                           |\n| 2     | 2                           |\n| 3     | 6                           |\n| 4     | 24                          |\n| 5     | 120                         |\n| 6     | 720                         |\n| 7     | 5 040                       |\n| 8     | 40 320                      |\n| 9     | 362 880                     |\n| 10    | 3 628 800                   |\n| 11    | 39 916 800                  |\n| 12    | 479 001 600                 |\n| 13    | 6 227 020 800               |\n| 14    | 87 178 291 200              |\n| 15    | 1 307 674 368 000           |\n\n"
  },
  {
    "path": "src/algorithms/math/factorial/__test__/factorial.test.js",
    "content": "import factorial from '../factorial';\n\ndescribe('factorial', () => {\n  it('should calculate factorial', () => {\n    expect(factorial(0)).toBe(1);\n    expect(factorial(1)).toBe(1);\n    expect(factorial(5)).toBe(120);\n    expect(factorial(8)).toBe(40320);\n    expect(factorial(10)).toBe(3628800);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/factorial/__test__/factorialRecursive.test.js",
    "content": "import factorialRecursive from '../factorialRecursive';\n\ndescribe('factorialRecursive', () => {\n  it('should calculate factorial', () => {\n    expect(factorialRecursive(0)).toBe(1);\n    expect(factorialRecursive(1)).toBe(1);\n    expect(factorialRecursive(5)).toBe(120);\n    expect(factorialRecursive(8)).toBe(40320);\n    expect(factorialRecursive(10)).toBe(3628800);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/factorial/factorial.js",
    "content": "/**\n * @param {number} number\n * @return {number}\n */\nexport default function factorial(number) {\n  let result = 1;\n\n  for (let i = 2; i <= number; i += 1) {\n    result *= i;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "src/algorithms/math/factorial/factorialRecursive.js",
    "content": "/**\n * @param {number} number\n * @return {number}\n */\nexport default function factorialRecursive(number) {\n  return number > 1 ? number * factorialRecursive(number - 1) : 1;\n}\n"
  },
  {
    "path": "src/algorithms/math/fast-powering/README.fr-FR.md",
    "content": "# Algorithme d'exponentiation rapide\n\n_Read this in other languages:_\n[english](README.md).\n\nEn 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.\n\nElle 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.\n\n![Power](https://www.mathsisfun.com/algebra/images/exponent-8-2.svg)\n\n## Implémentation « naïve »\n\nComment trouver `a` élevé à la puissance `b` ?\n\nOn multiplie `a` avec lui-même, `b` nombre de fois.\nAinsi, `a^b = a * a * a * ... * a` (`b` occurrences de `a`).\n\nCette opération aura un complexité linéaire, notée `O(n)`,\ncar la multiplication aura lieu exactement `n` fois.\n\n## Algorithme d'exponentiation rapide\n\nPeut-on faire mieux que cette implémentation naïve?\nOui, on peut réduire le nombre de puissance à un complexité de `O(log(n))`.\n\nCet algorithme utilise l'approche « diviser pour mieux régner »\npour calculer cette puissance.\nEn l'état, cet algorithme fonctionne pour deux entiers positifs `X` et `Y`.\n\nL'idée derrière cet algorithme est basée sur l'observation suivante.\n\nLorsque `Y` est **pair**:\n\n```text\nX^Y = X^(Y/2) * X^(Y/2)\n```\n\nLorsque `Y` est **impair**:\n\n```text\nX^Y = X^(Y//2) * X^(Y//2) * X\noù Y//2 est le résultat de la division entière de Y par 2.\n```\n\n**Par exemple**\n\n```text\n2^4 = (2 * 2) * (2 * 2) = (2^2) * (2^2)\n```\n\n```text\n2^5 = (2 * 2) * (2 * 2) * 2 = (2^2) * (2^2) * (2)\n```\n\nAinsi, puisqu'à chaque étape on doits calculer\ndeux fois la même puissance `X ^ (Y / 2)`,\non peut optimiser en l'enregistrant dans une variable intermédiaire\npour éviter son calcul en double.\n\n**Complexité en temps**\n\nComme à chaque itération nous réduisons la puissance de moitié,\nnous appelons récursivement la fonction `log(n)` fois. Le complexité de temps de cet algorithme est donc réduite à:\n\n```text\nO(log(n))\n```\n\n## Références\n\n- [YouTube](https://www.youtube.com/watch?v=LUWavfN9zEo&index=80&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)\n- [Wikipedia](https://fr.wikipedia.org/wiki/Exponentiation_rapide)\n"
  },
  {
    "path": "src/algorithms/math/fast-powering/README.md",
    "content": "# Fast Powering Algorithm\n\n_Read this in other languages:_\n[français](README.fr-FR.md).\n\n**The power of a number** says how many times to use the number in a\nmultiplication.\n\nIt is written as a small number to the right and above the base number.\n\n![Power](https://www.mathsisfun.com/algebra/images/exponent-8-2.svg)\n\n## Naive Algorithm Complexity\n\nHow to find `a` raised to the power `b`?\n\nWe multiply `a` to itself, `b` times. That\nis, `a^b = a * a * a * ... * a` (`b` occurrences of `a`).\n\nThis operation will take `O(n)` time since we need to do multiplication operation\nexactly `n` times.\n\n## Fast Power Algorithm\n\nCan we do better than naive algorithm does? Yes we may solve the task of\npowering in `O(log(n))` time.\n\nThe algorithm uses divide and conquer approach to compute power. Currently the\nalgorithm work for two positive integers `X` and `Y`.\n\nThe idea behind the algorithm is based on the fact that:\n\nFor **even** `Y`:\n\n```text\nX^Y = X^(Y/2) * X^(Y/2)\n```\n\nFor **odd** `Y`:\n\n```text\nX^Y = X^(Y//2) * X^(Y//2) * X\nwhere Y//2 is result of division of Y by 2 without reminder.\n```\n\n**For example**\n\n```text\n2^4 = (2 * 2) * (2 * 2) = (2^2) * (2^2)\n```\n\n```text\n2^5 = (2 * 2) * (2 * 2) * 2 = (2^2) * (2^2) * (2)\n```\n\nNow, since on each step we need to compute the same `X^(Y/2)` power twice we may optimise\nit by saving it to some intermediate variable to avoid its duplicate calculation.\n\n**Time Complexity**\n\nSince each iteration we split the power by half then we will call function\nrecursively `log(n)` times. This the time complexity of the algorithm is reduced to:\n\n```text\nO(log(n))\n```\n\n## References\n\n- [YouTube](https://www.youtube.com/watch?v=LUWavfN9zEo&index=80&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)\n- [Wikipedia](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)\n"
  },
  {
    "path": "src/algorithms/math/fast-powering/__test__/fastPowering.test.js",
    "content": "import fastPowering from '../fastPowering';\n\ndescribe('fastPowering', () => {\n  it('should compute power in log(n) time', () => {\n    expect(fastPowering(1, 1)).toBe(1);\n    expect(fastPowering(2, 0)).toBe(1);\n    expect(fastPowering(2, 2)).toBe(4);\n    expect(fastPowering(2, 3)).toBe(8);\n    expect(fastPowering(2, 4)).toBe(16);\n    expect(fastPowering(2, 5)).toBe(32);\n    expect(fastPowering(2, 6)).toBe(64);\n    expect(fastPowering(2, 7)).toBe(128);\n    expect(fastPowering(2, 8)).toBe(256);\n    expect(fastPowering(3, 4)).toBe(81);\n    expect(fastPowering(190, 2)).toBe(36100);\n    expect(fastPowering(11, 5)).toBe(161051);\n    expect(fastPowering(13, 11)).toBe(1792160394037);\n    expect(fastPowering(9, 16)).toBe(1853020188851841);\n    expect(fastPowering(16, 16)).toBe(18446744073709552000);\n    expect(fastPowering(7, 21)).toBe(558545864083284000);\n    expect(fastPowering(100, 9)).toBe(1000000000000000000);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/fast-powering/fastPowering.js",
    "content": "/**\n * Fast Powering Algorithm.\n * Recursive implementation to compute power.\n *\n * Complexity: log(n)\n *\n * @param {number} base - Number that will be raised to the power.\n * @param {number} power - The power that number will be raised to.\n * @return {number}\n */\nexport default function fastPowering(base, power) {\n  if (power === 0) {\n    // Anything that is raised to the power of zero is 1.\n    return 1;\n  }\n\n  if (power % 2 === 0) {\n    // If the power is even...\n    // we may recursively redefine the result via twice smaller powers:\n    // x^8 = x^4 * x^4.\n    const multiplier = fastPowering(base, power / 2);\n    return multiplier * multiplier;\n  }\n\n  // If the power is odd...\n  // we may recursively redefine the result via twice smaller powers:\n  // x^9 = x^4 * x^4 * x.\n  const multiplier = fastPowering(base, Math.floor(power / 2));\n  return multiplier * multiplier * base;\n}\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/README.fr-FR.md",
    "content": "# Nombre de Fibonacci\n\n_Read this in other languages:_\n[english](README.md),\n[ქართული](README.ka-GE.md).\n\nEn mathématiques, la suite de Fibonacci est une suite d'entiers\ndans laquelle chaque terme (après les deux premiers)\nest la somme des deux termes qui le précèdent.\nLes termes de cette suite sont appelés nombres de Fibonacci:\n\n`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`\n\nLes carrés de Fibonacci en spirale s'ajustent ensemble pour former une spirale d'or.\n\n![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)\n\nLa 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.\n\n![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)\n\n## References\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/Suite_de_Fibonacci)\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/README.ka-GE.md",
    "content": "# ფიბონაჩის რიცხვი\n\nმათემატიკაში ფიბონაჩის მიმდევრობა წარმოადგენს მთელ რიცხვთა მიმდევრობას,\nრომელშიც ყოველი რიცხვი (პირველი ორი რიცხვის შემდეგ)\nმისი წინამორბედი ორი რიცხვის\nჯამის ტოლია:\n\n`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`\n\nკვადრატების წყობა, სადაც ყოველი კვადრატის გვერდების სიგრძე, თანმიმდევრობით, ფიბონაჩის რიცხვებს შეესაბამება\n\n![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)\n\nფიბონაჩის სპირალი: ოქროს სპირალის აპროქსიმაცია, რომელიც შექმნილია კვადრატების მოპირდაპირე კუთხეებს შორის შემაერთებელი რკალების გავლებით;[4] ამ შემთხვევაში, გამოყენებულ კვადრატთა [გვერდების] ზომებია: 1, 1, 2, 3, 5, 8, 13 და 21.\n\n![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)\n\n## სქოლიო\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number)\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/README.md",
    "content": "# Fibonacci Number\n\n_Read this in other languages:_\n[français](README.fr-FR.md),\n[简体中文](README.zh-CN.md),\n[ქართული](README.ka-GE.md).\n\nIn mathematics, the Fibonacci numbers are the numbers in the following\ninteger sequence, called the Fibonacci sequence, and characterized by\nthe fact that every number after the first two is the sum of the two\npreceding ones:\n\n`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`\n\nA tiling with squares whose side lengths are successive Fibonacci numbers\n\n![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)\n\nThe 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.\n\n![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number)\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/README.zh-CN.md",
    "content": "# 斐波那契数\n\n_Read this in other languages:_\n[français](README.fr-FR.md),\n[english](README.md),\n[ქართული](README.ka-GE.md).\n\n在数学中，斐波那契数是以下整数序列（称为斐波那契数列）中的数字，其特征在于前两个数字之后的每个数字都是前两个数字的和：\n\n`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`\n\n边长为连续斐波纳契数的正方形平铺\n\n![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)\n\n\n斐波那契螺旋：通过绘制连接斐波那契平铺中正方形的相对角的圆弧而创建的金色螺旋的近似值； [4]该三角形使用大小为1、1、2、3、5、8、13和21的正方形。\n\n![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number)\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/__test__/fibonacci.test.js",
    "content": "import fibonacci from '../fibonacci';\n\ndescribe('fibonacci', () => {\n  it('should calculate fibonacci correctly', () => {\n    expect(fibonacci(1)).toEqual([1]);\n    expect(fibonacci(2)).toEqual([1, 1]);\n    expect(fibonacci(3)).toEqual([1, 1, 2]);\n    expect(fibonacci(4)).toEqual([1, 1, 2, 3]);\n    expect(fibonacci(5)).toEqual([1, 1, 2, 3, 5]);\n    expect(fibonacci(6)).toEqual([1, 1, 2, 3, 5, 8]);\n    expect(fibonacci(7)).toEqual([1, 1, 2, 3, 5, 8, 13]);\n    expect(fibonacci(8)).toEqual([1, 1, 2, 3, 5, 8, 13, 21]);\n    expect(fibonacci(9)).toEqual([1, 1, 2, 3, 5, 8, 13, 21, 34]);\n    expect(fibonacci(10)).toEqual([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/__test__/fibonacciNth.test.js",
    "content": "import fibonacciNth from '../fibonacciNth';\n\ndescribe('fibonacciNth', () => {\n  it('should calculate fibonacci correctly', () => {\n    expect(fibonacciNth(1)).toBe(1);\n    expect(fibonacciNth(2)).toBe(1);\n    expect(fibonacciNth(3)).toBe(2);\n    expect(fibonacciNth(4)).toBe(3);\n    expect(fibonacciNth(5)).toBe(5);\n    expect(fibonacciNth(6)).toBe(8);\n    expect(fibonacciNth(7)).toBe(13);\n    expect(fibonacciNth(8)).toBe(21);\n    expect(fibonacciNth(20)).toBe(6765);\n    expect(fibonacciNth(30)).toBe(832040);\n    expect(fibonacciNth(50)).toBe(12586269025);\n    expect(fibonacciNth(70)).toBe(190392490709135);\n    expect(fibonacciNth(71)).toBe(308061521170129);\n    expect(fibonacciNth(72)).toBe(498454011879264);\n    expect(fibonacciNth(73)).toBe(806515533049393);\n    expect(fibonacciNth(74)).toBe(1304969544928657);\n    expect(fibonacciNth(75)).toBe(2111485077978050);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/__test__/fibonacciNthClosedForm.test.js",
    "content": "import fibonacciNthClosedForm from '../fibonacciNthClosedForm';\n\ndescribe('fibonacciClosedForm', () => {\n  it('should throw an error when trying to calculate fibonacci for not allowed positions', () => {\n    const calculateFibonacciForNotAllowedPosition = () => {\n      fibonacciNthClosedForm(76);\n    };\n\n    expect(calculateFibonacciForNotAllowedPosition).toThrow();\n  });\n\n  it('should calculate fibonacci correctly', () => {\n    expect(fibonacciNthClosedForm(1)).toBe(1);\n    expect(fibonacciNthClosedForm(2)).toBe(1);\n    expect(fibonacciNthClosedForm(3)).toBe(2);\n    expect(fibonacciNthClosedForm(4)).toBe(3);\n    expect(fibonacciNthClosedForm(5)).toBe(5);\n    expect(fibonacciNthClosedForm(6)).toBe(8);\n    expect(fibonacciNthClosedForm(7)).toBe(13);\n    expect(fibonacciNthClosedForm(8)).toBe(21);\n    expect(fibonacciNthClosedForm(20)).toBe(6765);\n    expect(fibonacciNthClosedForm(30)).toBe(832040);\n    expect(fibonacciNthClosedForm(50)).toBe(12586269025);\n    expect(fibonacciNthClosedForm(70)).toBe(190392490709135);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/fibonacci.js",
    "content": "/**\n * Return a fibonacci sequence as an array.\n *\n * @param n\n * @return {number[]}\n */\nexport default function fibonacci(n) {\n  const fibSequence = [1];\n\n  let currentValue = 1;\n  let previousValue = 0;\n\n  if (n === 1) {\n    return fibSequence;\n  }\n\n  let iterationsCounter = n - 1;\n\n  while (iterationsCounter) {\n    currentValue += previousValue;\n    previousValue = currentValue - previousValue;\n\n    fibSequence.push(currentValue);\n\n    iterationsCounter -= 1;\n  }\n\n  return fibSequence;\n}\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/fibonacciNth.js",
    "content": "/**\n * Calculate fibonacci number at specific position using Dynamic Programming approach.\n *\n * @param n\n * @return {number}\n */\nexport default function fibonacciNth(n) {\n  let currentValue = 1;\n  let previousValue = 0;\n\n  if (n === 1) {\n    return 1;\n  }\n\n  let iterationsCounter = n - 1;\n\n  while (iterationsCounter) {\n    currentValue += previousValue;\n    previousValue = currentValue - previousValue;\n\n    iterationsCounter -= 1;\n  }\n\n  return currentValue;\n}\n"
  },
  {
    "path": "src/algorithms/math/fibonacci/fibonacciNthClosedForm.js",
    "content": "/**\n * Calculate fibonacci number at specific position using closed form function (Binet's formula).\n * @see: https://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression\n *\n * @param {number} position - Position number of fibonacci sequence (must be number from 1 to 75).\n * @return {number}\n */\nexport default function fibonacciClosedForm(position) {\n  const topMaxValidPosition = 70;\n\n  // Check that position is valid.\n  if (position < 1 || position > topMaxValidPosition) {\n    throw new Error(`Can't handle position smaller than 1 or greater than ${topMaxValidPosition}`);\n  }\n\n  // Calculate √5 to re-use it in further formulas.\n  const sqrt5 = Math.sqrt(5);\n  // Calculate φ constant (≈ 1.61803).\n  const phi = (1 + sqrt5) / 2;\n\n  // Calculate fibonacci number using Binet's formula.\n  return Math.floor((phi ** position) / sqrt5 + 0.5);\n}\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/README.fr-FR.md",
    "content": "# Transformation de Fourier\n\n_Read this in other languages:_\n[english](README.md).\n\n## Définitions\n\nLa transformation de Fourier (**ℱ**) est une opération qui transforme\nune fonction intégrable sur ℝ en une autre fonction,\ndécrivant le spectre fréquentiel de cette dernière\n\nLa **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.\nL'intervalle auquel le TFtd est échantillonné est l'inverse de la durée de la séquence d'entrée.\nUne 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\nséquence d'entrée originale. On dit donc que la TFD est une représentation du domaine fréquentiel\nde la séquence d'entrée d'origine. Si la séquence d'origine couvre toutes les\nvaleurs non nulles d'une fonction, sa TFtd est continue (et périodique), et la TFD fournit\nles é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.\n\nTransformée de Fourier Discrète converti une séquence de `N` nombres complexes:\n\n{x<sub>n</sub>} = x<sub>0</sub>, x<sub>1</sub>, x<sub>2</sub> ..., x<sub>N-1</sub>\n\nen une atre séquence de nombres complexes::\n\n{X<sub>k</sub>} = X<sub>0</sub>, X<sub>1</sub>, X<sub>2</sub> ..., X<sub>N-1</sub>\n\ndécrite par:\n\n![DFT](https://wikimedia.org/api/rest_v1/media/math/render/svg/1af0a78dc50bbf118ab6bd4c4dcc3c4ff8502223)\n\nThe **Transformée de Fourier à temps discret** (**TFtd**) est une forme d'analyse de Fourier\nqui 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\n(échantillons) dont l'intervalle a souvent des unités de temps.\nÀ partir des seuls échantillons, elle produit une fonction de fréquence qui est une somme périodique de la\nTransformée de Fourier continue de la fonction continue d'origine.\n\nA **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).\n\nCette transformation peut être illustée par la formule suivante. Sur la période de temps mesurée\ndans le diagramme, le signal contient 3 fréquences dominantes distinctes.\n\nVue d'un signal dans le domaine temporel et fréquentiel:\n\n![FFT](https://upload.wikimedia.org/wikipedia/commons/6/61/FFT-Time-Frequency-View.png)\n\nAn FFT algorithm computes the discrete Fourier transform (DFT) of a sequence, or\nits inverse (IFFT). Fourier analysis converts a signal from its original domain\nto a representation in the frequency domain and vice versa. An FFT rapidly\ncomputes such transformations by factorizing the DFT matrix into a product of\nsparse (mostly zero) factors. As a result, it manages to reduce the complexity of\ncomputing the DFT from O(n<sup>2</sup>), which arises if one simply applies the\ndefinition of DFT, to O(n log n), where n is the data size.\n\nUn algorithme FFT calcule la Transformée de Fourier discrète (TFD) d'une séquence, ou\nson inverse (IFFT). L'analyse de Fourier convertit un signal de son domaine d'origine\nen une représentation dans le domaine fréquentiel et vice versa. Une FFT\ncalcule rapidement ces transformations en factorisant la matrice TFD en un produit de\nfacteurs dispersés (généralement nuls). En conséquence, il parvient à réduire la complexité de\ncalcul de la TFD de O (n <sup> 2 </sup>), qui survient si l'on applique simplement la\ndéfinition de TFD, à O (n log n), où n est la taille des données.\n\nVoici une analyse de Fourier discrète d'une somme d'ondes cosinus à 10, 20, 30, 40,\net 50 Hz:\n\n![FFT](https://upload.wikimedia.org/wikipedia/commons/6/64/FFT_of_Cosine_Summation_Function.png)\n\n## Explanation\n\nLa Transformée de Fourier est l'une des connaissances les plus importante jamais découverte. Malheureusement, le\nson sens est enfoui dans des équations denses::\n\n![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/45c088dbb767150fc0bacfeb49dd49e5.png)\n\net\n\n![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/faeb9c5bf2e60add63ae4a70b293c7b4.png)\n\nPlutô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:\n\n- _Que fait la transformée de Fourier ?_ A partir d'un smoothie, elle trouve sa recette.\n- _Comment ?_ Elle passe le smoothie dans un filtre pour en extraire chaque ingrédient.\n- _Pourquoi ?_ Les recettes sont plus faciles à analyser, comparer et modifier que le smoothie lui-même.\n- _Comment récupérer le smoothie ?_ Re-mélanger les ingrédients.\n\n**Pensez en cercles, pas seulement en sinusoïdes**\n\nLa transformée de Fourier concerne des trajectoires circulaires (pas les sinusoïdes 1-d)\net la formuled'Euler est une manière intelligente d'en générer une:\n\n![](https://betterexplained.com/wp-content/uploads/euler/equal_paths.png)\n\nDoit-on utiliser des exposants imaginaires pour se déplacer en cercle ? Non. Mais c'est pratique\net compact. Et bien sûr, nous pouvons décrire notre chemin comme un mouvement coordonné en deux\ndimensions (réelle et imaginaire), mais n'oubliez pas la vue d'ensemble: nous sommes juste\nen déplacement dans un cercle.\n\n**À la découverte de la transformation complète**\n\nL'idée générale: notre signal n'est qu'un tas de pics de temps, d'instant T ! Si nous combinons les\nrecettes pour chaque pic de temps, nous devrions obtenir la recette du signal complet.\n\nLa transformée de Fourier construit cette recette fréquence par fréquence:\n\n![](https://betterexplained.com/wp-content/uploads/images/fourier-explained-20121219-224649.png)\n\nQuelques notes\n\n- N = nombre d'échantillons de temps dont nous disposons\n- n = échantillon actuellement étudié (0 ... N-1)\n- x<sub>n</sub> = valeur du signal au temps n\n- k = fréquence actuellement étudiée (0 Hertz up to N-1 Hertz)\n- X<sub>k</sub> = quantité de fréquence k dans le signal (amplitude et phase, un nombre complexe)\n- 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/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.\n- 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.\n\nStuart Riffle a une excellente interprétation de la transformée de Fourier:\n\n![](https://betterexplained.com/wp-content/uploads/images/DerivedDFT.png)\n\n## Références\n\n- Wikipedia\n\n  - [TF](https://fr.wikipedia.org/wiki/Transformation_de_Fourier)\n  - [TFD](https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te)\n  - [FFT](https://fr.wikipedia.org/wiki/Transformation_de_Fourier_rapide)\n  - [TFtd (en anglais)](https://en.wikipedia.org/wiki/Discrete-time_Fourier_transform)\n\n- en Anglais\n  - [An Interactive Guide To The Fourier Transform](https://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/)\n  - [DFT on YouTube by Better Explained](https://www.youtube.com/watch?v=iN0VG9N2q0U&t=0s&index=77&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n  - [FT on YouTube by 3Blue1Brown](https://www.youtube.com/watch?v=spUNpyF58BY&t=0s&index=76&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n  - [FFT on YouTube by Simon Xu](https://www.youtube.com/watch?v=htCj9exbGo0&index=78&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/README.md",
    "content": "# Fourier Transform\n\n_Read this in other languages:_\n[français](README.fr-FR.md).\n\n## Definitions\n\nThe **Fourier Transform** (**FT**) decomposes a function of time (a signal) into\nthe frequencies that make it up, in a way similar to how a musical chord can be\nexpressed as the frequencies (or pitches) of its constituent notes.\n\nThe **Discrete Fourier Transform** (**DFT**) converts a finite sequence of\nequally-spaced samples of a function into a same-length sequence of\nequally-spaced samples of the discrete-time Fourier transform (DTFT), which is a\ncomplex-valued function of frequency. The interval at which the DTFT is sampled\nis the reciprocal of the duration of the input sequence. An inverse DFT is a\nFourier series, using the DTFT samples as coefficients of complex sinusoids at\nthe corresponding DTFT frequencies. It has the same sample-values as the original\ninput sequence. The DFT is therefore said to be a frequency domain representation\nof the original input sequence. If the original sequence spans all the non-zero\nvalues of a function, its DTFT is continuous (and periodic), and the DFT provides\ndiscrete samples of one cycle. If the original sequence is one cycle of a periodic\nfunction, the DFT provides all the non-zero values of one DTFT cycle.\n\nThe Discrete Fourier transform transforms a sequence of `N` complex numbers:\n\n{x<sub>n</sub>} = x<sub>0</sub>, x<sub>1</sub>, x<sub>2</sub> ..., x<sub>N-1</sub>\n\ninto another sequence of complex numbers:\n\n{X<sub>k</sub>} = X<sub>0</sub>, X<sub>1</sub>, X<sub>2</sub> ..., X<sub>N-1</sub>\n\nwhich is defined by:\n\n![DFT](https://wikimedia.org/api/rest_v1/media/math/render/svg/1af0a78dc50bbf118ab6bd4c4dcc3c4ff8502223)\n\nThe **Discrete-Time Fourier Transform** (**DTFT**) is a form of Fourier analysis\nthat is applicable to the uniformly-spaced samples of a continuous function. The\nterm discrete-time refers to the fact that the transform operates on discrete data\n(samples) whose interval often has units of time. From only the samples, it\nproduces a function of frequency that is a periodic summation of the continuous\nFourier transform of the original continuous function.\n\nA **Fast Fourier Transform** (**FFT**) is an algorithm that samples a signal over\na period of time (or space) and divides it into its frequency components. These\ncomponents are single sinusoidal oscillations at distinct frequencies each with\ntheir own amplitude and phase.\n\nThis transformation is illustrated in Diagram below. Over the time period measured\nin the diagram, the signal contains 3 distinct dominant frequencies.\n\nView of a signal in the time and frequency domain:\n\n![FFT](https://upload.wikimedia.org/wikipedia/commons/6/61/FFT-Time-Frequency-View.png)\n\nAn FFT algorithm computes the discrete Fourier transform (DFT) of a sequence, or\nits inverse (IFFT). Fourier analysis converts a signal from its original domain\nto a representation in the frequency domain and vice versa. An FFT rapidly\ncomputes such transformations by factorizing the DFT matrix into a product of\nsparse (mostly zero) factors. As a result, it manages to reduce the complexity of\ncomputing the DFT from O(n<sup>2</sup>), which arises if one simply applies the\ndefinition of DFT, to O(n log n), where n is the data size.\n\nHere a discrete Fourier analysis of a sum of cosine waves at 10, 20, 30, 40,\nand 50 Hz:\n\n![FFT](https://upload.wikimedia.org/wikipedia/commons/6/64/FFT_of_Cosine_Summation_Function.png)\n\n## Explanation\n\nThe Fourier Transform is one of deepest insights ever made. Unfortunately, the\nmeaning is buried within dense equations:\n\n![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/45c088dbb767150fc0bacfeb49dd49e5.png)\n\nand\n\n![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/faeb9c5bf2e60add63ae4a70b293c7b4.png)\n\nRather than jumping into the symbols, let's experience the key idea firsthand. Here's a plain-English metaphor:\n\n- _What does the Fourier Transform do?_ Given a smoothie, it finds the recipe.\n- _How?_ Run the smoothie through filters to extract each ingredient.\n- _Why?_ Recipes are easier to analyze, compare, and modify than the smoothie itself.\n- _How do we get the smoothie back?_ Blend the ingredients.\n\n**Think With Circles, Not Just Sinusoids**\n\nThe Fourier Transform is about circular paths (not 1-d sinusoids) and Euler's\nformula is a clever way to generate one:\n\n![](https://betterexplained.com/wp-content/uploads/euler/equal_paths.png)\n\nMust we use imaginary exponents to move in a circle? Nope. But it's convenient\nand compact. And sure, we can describe our path as coordinated motion in two\ndimensions (real and imaginary), but don't forget the big picture: we're just\nmoving in a circle.\n\n**Discovering The Full Transform**\n\nThe big insight: our signal is just a bunch of time spikes! If we merge the\nrecipes for each time spike, we should get the recipe for the full signal.\n\nThe Fourier Transform builds the recipe frequency-by-frequency:\n\n![](https://betterexplained.com/wp-content/uploads/images/fourier-explained-20121219-224649.png)\n\nA few notes:\n\n- N = number of time samples we have\n- n = current sample we're considering (0 ... N-1)\n- x<sub>n</sub> = value of the signal at time n\n- k = current frequency we're considering (0 Hertz up to N-1 Hertz)\n- X<sub>k</sub> = amount of frequency k in the signal (amplitude and phase, a complex number)\n- 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/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.\n- 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\nStuart Riffle has a great interpretation of the Fourier Transform:\n\n![](https://betterexplained.com/wp-content/uploads/images/DerivedDFT.png)\n\n## References\n\n- [An Interactive Guide To The Fourier Transform](https://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/)\n- [DFT on YouTube by Better Explained](https://www.youtube.com/watch?v=iN0VG9N2q0U&t=0s&index=77&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [FT on YouTube by 3Blue1Brown](https://www.youtube.com/watch?v=spUNpyF58BY&t=0s&index=76&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [FFT on YouTube by Simon Xu](https://www.youtube.com/watch?v=htCj9exbGo0&index=78&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)\n- Wikipedia\n  - [FT](https://en.wikipedia.org/wiki/Fourier_transform)\n  - [DFT](https://www.wikiwand.com/en/Discrete_Fourier_transform)\n  - [DTFT](https://en.wikipedia.org/wiki/Discrete-time_Fourier_transform)\n  - [FFT](https://www.wikiwand.com/en/Fast_Fourier_transform)\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/__test__/FourierTester.js",
    "content": "import ComplexNumber from '../../complex-number/ComplexNumber';\n\nexport const fourierTestCases = [\n  {\n    input: [\n      { amplitude: 1 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 1, phase: 0, re: 1, im: 0,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 1 },\n      { amplitude: 0 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 0.5, phase: 0, re: 0.5, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.5, phase: 0, re: 0.5, im: 0,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 2 },\n      { amplitude: 0 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 1, phase: 0, re: 1, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 1, phase: 0, re: 1, im: 0,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 1 },\n      { amplitude: 0 },\n      { amplitude: 0 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 0.33333, phase: 0, re: 0.33333, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.33333, phase: 0, re: 0.33333, im: 0,\n      },\n      {\n        frequency: 2, amplitude: 0.33333, phase: 0, re: 0.33333, im: 0,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 1 },\n      { amplitude: 0 },\n      { amplitude: 0 },\n      { amplitude: 0 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n      {\n        frequency: 2, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 0 },\n      { amplitude: 1 },\n      { amplitude: 0 },\n      { amplitude: 0 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.25, phase: -90, re: 0, im: -0.25,\n      },\n      {\n        frequency: 2, amplitude: 0.25, phase: 180, re: -0.25, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 0.25, phase: 90, re: 0, im: 0.25,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 0 },\n      { amplitude: 0 },\n      { amplitude: 1 },\n      { amplitude: 0 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.25, phase: 180, re: -0.25, im: 0,\n      },\n      {\n        frequency: 2, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 0.25, phase: 180, re: -0.25, im: 0,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 0 },\n      { amplitude: 0 },\n      { amplitude: 0 },\n      { amplitude: 2 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 0.5, phase: 0, re: 0.5, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.5, phase: 90, re: 0, im: 0.5,\n      },\n      {\n        frequency: 2, amplitude: 0.5, phase: 180, re: -0.5, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 0.5, phase: -90, re: 0, im: -0.5,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 0 },\n      { amplitude: 1 },\n      { amplitude: 0 },\n      { amplitude: 2 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 0.75, phase: 0, re: 0.75, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.25, phase: 90, re: 0, im: 0.25,\n      },\n      {\n        frequency: 2, amplitude: 0.75, phase: 180, re: -0.75, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 0.25, phase: -90, re: 0, im: -0.25,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 4 },\n      { amplitude: 1 },\n      { amplitude: 0 },\n      { amplitude: 2 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 1.75, phase: 0, re: 1.75, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 1.03077, phase: 14.03624, re: 0.99999, im: 0.25,\n      },\n      {\n        frequency: 2, amplitude: 0.25, phase: 0, re: 0.25, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 1.03077, phase: -14.03624, re: 1, im: -0.25,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 4 },\n      { amplitude: 1 },\n      { amplitude: -3 },\n      { amplitude: 2 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 1, phase: 0, re: 1, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 1.76776, phase: 8.13010, re: 1.75, im: 0.25,\n      },\n      {\n        frequency: 2, amplitude: 0.5, phase: 180, re: -0.5, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 1.76776, phase: -8.13010, re: 1.75, im: -0.24999,\n      },\n    ],\n  },\n  {\n    input: [\n      { amplitude: 1 },\n      { amplitude: 2 },\n      { amplitude: 3 },\n      { amplitude: 4 },\n    ],\n    output: [\n      {\n        frequency: 0, amplitude: 2.5, phase: 0, re: 2.5, im: 0,\n      },\n      {\n        frequency: 1, amplitude: 0.70710, phase: 135, re: -0.5, im: 0.49999,\n      },\n      {\n        frequency: 2, amplitude: 0.5, phase: 180, re: -0.5, im: 0,\n      },\n      {\n        frequency: 3, amplitude: 0.70710, phase: -134.99999, re: -0.49999, im: -0.5,\n      },\n    ],\n  },\n];\n\nexport default class FourierTester {\n  /**\n   * @param {function} fourierTransform\n   */\n  static testDirectFourierTransform(fourierTransform) {\n    fourierTestCases.forEach((testCase) => {\n      const { input, output: expectedOutput } = testCase;\n\n      // Try to split input signal into sequence of pure sinusoids.\n      const formattedInput = input.map((sample) => sample.amplitude);\n      const currentOutput = fourierTransform(formattedInput);\n\n      // Check the signal has been split into proper amount of sub-signals.\n      expect(currentOutput.length).toBeGreaterThanOrEqual(formattedInput.length);\n\n      // Now go through all the signals and check their frequency, amplitude and phase.\n      expectedOutput.forEach((expectedSignal, frequency) => {\n        // Get template data we want to test against.\n        const currentSignal = currentOutput[frequency];\n        const currentPolarSignal = currentSignal.getPolarForm(false);\n\n        // Check all signal parameters.\n        expect(frequency).toBe(expectedSignal.frequency);\n        expect(currentSignal.re).toBeCloseTo(expectedSignal.re, 4);\n        expect(currentSignal.im).toBeCloseTo(expectedSignal.im, 4);\n        expect(currentPolarSignal.phase).toBeCloseTo(expectedSignal.phase, 4);\n        expect(currentPolarSignal.radius).toBeCloseTo(expectedSignal.amplitude, 4);\n      });\n    });\n  }\n\n  /**\n   * @param {function} inverseFourierTransform\n   */\n  static testInverseFourierTransform(inverseFourierTransform) {\n    fourierTestCases.forEach((testCase) => {\n      const { input: expectedOutput, output: inputFrequencies } = testCase;\n\n      // Try to join frequencies into time signal.\n      const formattedInput = inputFrequencies.map((frequency) => {\n        return new ComplexNumber({ re: frequency.re, im: frequency.im });\n      });\n      const currentOutput = inverseFourierTransform(formattedInput);\n\n      // Check the signal has been combined of proper amount of time samples.\n      expect(currentOutput.length).toBeLessThanOrEqual(formattedInput.length);\n\n      // Now go through all the amplitudes and check their values.\n      expectedOutput.forEach((expectedAmplitudes, timer) => {\n        // Get template data we want to test against.\n        const currentAmplitude = currentOutput[timer];\n\n        // Check if current amplitude is close enough to the calculated one.\n        expect(currentAmplitude).toBeCloseTo(expectedAmplitudes.amplitude, 4);\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/__test__/discreteFourierTransform.test.js",
    "content": "import discreteFourierTransform from '../discreteFourierTransform';\nimport FourierTester from './FourierTester';\n\ndescribe('discreteFourierTransform', () => {\n  it('should split signal into frequencies', () => {\n    FourierTester.testDirectFourierTransform(discreteFourierTransform);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/__test__/fastFourierTransform.test.js",
    "content": "import fastFourierTransform from '../fastFourierTransform';\nimport ComplexNumber from '../../complex-number/ComplexNumber';\n\n/**\n * @param {ComplexNumber[]} sequence1\n * @param {ComplexNumber[]} sequence2\n * @param {Number} delta\n * @return {boolean}\n */\nfunction sequencesApproximatelyEqual(sequence1, sequence2, delta) {\n  if (sequence1.length !== sequence2.length) {\n    return false;\n  }\n\n  for (let numberIndex = 0; numberIndex < sequence1.length; numberIndex += 1) {\n    if (Math.abs(sequence1[numberIndex].re - sequence2[numberIndex].re) > delta) {\n      return false;\n    }\n\n    if (Math.abs(sequence1[numberIndex].im - sequence2[numberIndex].im) > delta) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nconst delta = 1e-6;\n\ndescribe('fastFourierTransform', () => {\n  it('should calculate the radix-2 discrete fourier transform #1', () => {\n    const input = [new ComplexNumber({ re: 0, im: 0 })];\n    const expectedOutput = [new ComplexNumber({ re: 0, im: 0 })];\n    const output = fastFourierTransform(input);\n    const invertedOutput = fastFourierTransform(output, true);\n\n    expect(sequencesApproximatelyEqual(expectedOutput, output, delta)).toBe(true);\n    expect(sequencesApproximatelyEqual(input, invertedOutput, delta)).toBe(true);\n  });\n\n  it('should calculate the radix-2 discrete fourier transform #2', () => {\n    const input = [\n      new ComplexNumber({ re: 1, im: 2 }),\n      new ComplexNumber({ re: 2, im: 3 }),\n      new ComplexNumber({ re: 8, im: 4 }),\n    ];\n\n    const expectedOutput = [\n      new ComplexNumber({ re: 11, im: 9 }),\n      new ComplexNumber({ re: -10, im: 0 }),\n      new ComplexNumber({ re: 7, im: 3 }),\n      new ComplexNumber({ re: -4, im: -4 }),\n    ];\n\n    const output = fastFourierTransform(input);\n    const invertedOutput = fastFourierTransform(output, true);\n\n    expect(sequencesApproximatelyEqual(expectedOutput, output, delta)).toBe(true);\n    expect(sequencesApproximatelyEqual(input, invertedOutput, delta)).toBe(true);\n  });\n\n  it('should calculate the radix-2 discrete fourier transform #3', () => {\n    const input = [\n      new ComplexNumber({ re: -83656.9359385182, im: 98724.08038374918 }),\n      new ComplexNumber({ re: -47537.415125808424, im: 88441.58381765135 }),\n      new ComplexNumber({ re: -24849.657029355192, im: -72621.79007878687 }),\n      new ComplexNumber({ re: 31451.27290052717, im: -21113.301128347346 }),\n      new ComplexNumber({ re: 13973.90836288876, im: -73378.36721594246 }),\n      new ComplexNumber({ re: 14981.520420492234, im: 63279.524958963884 }),\n      new ComplexNumber({ re: -9892.575367044381, im: -81748.44671677813 }),\n      new ComplexNumber({ re: -35933.00356823792, im: -46153.47157161784 }),\n      new ComplexNumber({ re: -22425.008561855735, im: -86284.24507370662 }),\n      new ComplexNumber({ re: -39327.43830818355, im: 30611.949874562706 }),\n    ];\n\n    const expectedOutput = [\n      new ComplexNumber({ re: -203215.3322151, im: -100242.4827503 }),\n      new ComplexNumber({ re: 99217.0805705, im: 270646.9331932 }),\n      new ComplexNumber({ re: -305990.9040412, im: 68224.8435751 }),\n      new ComplexNumber({ re: -14135.7758282, im: 199223.9878095 }),\n      new ComplexNumber({ re: -306965.6350922, im: 26030.1025439 }),\n      new ComplexNumber({ re: -76477.6755206, im: 40781.9078990 }),\n      new ComplexNumber({ re: -48409.3099088, im: 54674.7959662 }),\n      new ComplexNumber({ re: -329683.0131713, im: 164287.7995937 }),\n      new ComplexNumber({ re: -50485.2048527, im: -330375.0546527 }),\n      new ComplexNumber({ re: 122235.7738708, im: 91091.6398019 }),\n      new ComplexNumber({ re: 47625.8850387, im: 73497.3981523 }),\n      new ComplexNumber({ re: -15619.8231136, im: 80804.8685410 }),\n      new ComplexNumber({ re: 192234.0276101, im: 160833.3072355 }),\n      new ComplexNumber({ re: -96389.4195635, im: 393408.4543872 }),\n      new ComplexNumber({ re: -173449.0825417, im: 146875.7724104 }),\n      new ComplexNumber({ re: -179002.5662573, im: 239821.0124341 }),\n    ];\n\n    const output = fastFourierTransform(input);\n    const invertedOutput = fastFourierTransform(output, true);\n\n    expect(sequencesApproximatelyEqual(expectedOutput, output, delta)).toBe(true);\n    expect(sequencesApproximatelyEqual(input, invertedOutput, delta)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/__test__/inverseDiscreteFourierTransform.test.js",
    "content": "import inverseDiscreteFourierTransform from '../inverseDiscreteFourierTransform';\nimport FourierTester from './FourierTester';\n\ndescribe('inverseDiscreteFourierTransform', () => {\n  it('should calculate output signal out of input frequencies', () => {\n    FourierTester.testInverseFourierTransform(inverseDiscreteFourierTransform);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/discreteFourierTransform.js",
    "content": "import ComplexNumber from '../complex-number/ComplexNumber';\n\nconst CLOSE_TO_ZERO_THRESHOLD = 1e-10;\n\n/**\n * Discrete Fourier Transform (DFT): time to frequencies.\n *\n * Time complexity: O(N^2)\n *\n * @param {number[]} inputAmplitudes - Input signal amplitudes over time (complex\n * numbers with real parts only).\n * @param {number} zeroThreshold - Threshold that is used to convert real and imaginary numbers\n * to zero in case if they are smaller then this.\n *\n * @return {ComplexNumber[]} - Array of complex number. Each of the number represents the frequency\n * or signal. All signals together will form input signal over discrete time periods. Each signal's\n * complex number has radius (amplitude) and phase (angle) in polar form that describes the signal.\n *\n * @see https://gist.github.com/anonymous/129d477ddb1c8025c9ac\n * @see https://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/\n */\nexport default function dft(inputAmplitudes, zeroThreshold = CLOSE_TO_ZERO_THRESHOLD) {\n  const N = inputAmplitudes.length;\n  const signals = [];\n\n  // Go through every discrete frequency.\n  for (let frequency = 0; frequency < N; frequency += 1) {\n    // Compound signal at current frequency that will ultimately\n    // take part in forming input amplitudes.\n    let frequencySignal = new ComplexNumber();\n\n    // Go through every discrete point in time.\n    for (let timer = 0; timer < N; timer += 1) {\n      const currentAmplitude = inputAmplitudes[timer];\n\n      // Calculate rotation angle.\n      const rotationAngle = -1 * (2 * Math.PI) * frequency * (timer / N);\n\n      // Remember that e^ix = cos(x) + i * sin(x);\n      const dataPointContribution = new ComplexNumber({\n        re: Math.cos(rotationAngle),\n        im: Math.sin(rotationAngle),\n      }).multiply(currentAmplitude);\n\n      // Add this data point's contribution.\n      frequencySignal = frequencySignal.add(dataPointContribution);\n    }\n\n    // Close to zero? You're zero.\n    if (Math.abs(frequencySignal.re) < zeroThreshold) {\n      frequencySignal.re = 0;\n    }\n\n    if (Math.abs(frequencySignal.im) < zeroThreshold) {\n      frequencySignal.im = 0;\n    }\n\n    // Average contribution at this frequency.\n    // The 1/N factor is usually moved to the reverse transform (going from frequencies\n    // back to time). This is allowed, though it would be nice to have 1/N in the forward\n    // transform since it gives the actual sizes for the time spikes.\n    frequencySignal = frequencySignal.divide(N);\n\n    // Add current frequency signal to the list of compound signals.\n    signals[frequency] = frequencySignal;\n  }\n\n  return signals;\n}\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/fastFourierTransform.js",
    "content": "import ComplexNumber from '../complex-number/ComplexNumber';\nimport bitLength from '../bits/bitLength';\n\n/**\n * Returns the number which is the flipped binary representation of input.\n *\n * @param {number} input\n * @param {number} bitsCount\n * @return {number}\n */\nfunction reverseBits(input, bitsCount) {\n  let reversedBits = 0;\n\n  for (let bitIndex = 0; bitIndex < bitsCount; bitIndex += 1) {\n    reversedBits *= 2;\n\n    if (Math.floor(input / (1 << bitIndex)) % 2 === 1) {\n      reversedBits += 1;\n    }\n  }\n\n  return reversedBits;\n}\n\n/**\n * Returns the radix-2 fast fourier transform of the given array.\n * Optionally computes the radix-2 inverse fast fourier transform.\n *\n * @param {ComplexNumber[]} inputData\n * @param {boolean} [inverse]\n * @return {ComplexNumber[]}\n */\nexport default function fastFourierTransform(inputData, inverse = false) {\n  const bitsCount = bitLength(inputData.length - 1);\n  const N = 1 << bitsCount;\n\n  while (inputData.length < N) {\n    inputData.push(new ComplexNumber());\n  }\n\n  const output = [];\n  for (let dataSampleIndex = 0; dataSampleIndex < N; dataSampleIndex += 1) {\n    output[dataSampleIndex] = inputData[reverseBits(dataSampleIndex, bitsCount)];\n  }\n\n  for (let blockLength = 2; blockLength <= N; blockLength *= 2) {\n    const imaginarySign = inverse ? -1 : 1;\n    const phaseStep = new ComplexNumber({\n      re: Math.cos((2 * Math.PI) / blockLength),\n      im: imaginarySign * Math.sin((2 * Math.PI) / blockLength),\n    });\n\n    for (let blockStart = 0; blockStart < N; blockStart += blockLength) {\n      let phase = new ComplexNumber({ re: 1, im: 0 });\n\n      for (let signalId = blockStart; signalId < (blockStart + blockLength / 2); signalId += 1) {\n        const component = output[signalId + blockLength / 2].multiply(phase);\n\n        const upd1 = output[signalId].add(component);\n        const upd2 = output[signalId].subtract(component);\n\n        output[signalId] = upd1;\n        output[signalId + blockLength / 2] = upd2;\n\n        phase = phase.multiply(phaseStep);\n      }\n    }\n  }\n\n  if (inverse) {\n    for (let signalId = 0; signalId < N; signalId += 1) {\n      output[signalId] /= N;\n    }\n  }\n\n  return output;\n}\n"
  },
  {
    "path": "src/algorithms/math/fourier-transform/inverseDiscreteFourierTransform.js",
    "content": "import ComplexNumber from '../complex-number/ComplexNumber';\n\nconst CLOSE_TO_ZERO_THRESHOLD = 1e-10;\n\n/**\n * Inverse Discrete Fourier Transform (IDFT): frequencies to time.\n *\n * Time complexity: O(N^2)\n *\n * @param {ComplexNumber[]} frequencies - Frequencies summands of the final signal.\n * @param {number} zeroThreshold - Threshold that is used to convert real and imaginary numbers\n * to zero in case if they are smaller then this.\n *\n * @return {number[]} - Discrete amplitudes distributed in time.\n */\nexport default function inverseDiscreteFourierTransform(\n  frequencies,\n  zeroThreshold = CLOSE_TO_ZERO_THRESHOLD,\n) {\n  const N = frequencies.length;\n  const amplitudes = [];\n\n  // Go through every discrete point of time.\n  for (let timer = 0; timer < N; timer += 1) {\n    // Compound amplitude at current time.\n    let amplitude = new ComplexNumber();\n\n    // Go through all discrete frequencies.\n    for (let frequency = 0; frequency < N; frequency += 1) {\n      const currentFrequency = frequencies[frequency];\n\n      // Calculate rotation angle.\n      const rotationAngle = (2 * Math.PI) * frequency * (timer / N);\n\n      // Remember that e^ix = cos(x) + i * sin(x);\n      const frequencyContribution = new ComplexNumber({\n        re: Math.cos(rotationAngle),\n        im: Math.sin(rotationAngle),\n      }).multiply(currentFrequency);\n\n      amplitude = amplitude.add(frequencyContribution);\n    }\n\n    // Close to zero? You're zero.\n    if (Math.abs(amplitude.re) < zeroThreshold) {\n      amplitude.re = 0;\n    }\n\n    if (Math.abs(amplitude.im) < zeroThreshold) {\n      amplitude.im = 0;\n    }\n\n    // Add current frequency signal to the list of compound signals.\n    amplitudes[timer] = amplitude.re;\n  }\n\n  return amplitudes;\n}\n"
  },
  {
    "path": "src/algorithms/math/horner-method/README.md",
    "content": "# Horner's Method\n\nIn 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`.\n\nHorner's method can be based on the following identity:\n\n![Horner's rule](https://wikimedia.org/api/rest_v1/media/math/render/svg/2a576e42d875496f8b0f0dda5ebff7c2415532e4)\n\nThis identity is called _Horner's rule_.\n\nTo 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. \n\n**Using the polynomial:**\n`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).\n\nNow, **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.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Horner%27s_method)\n"
  },
  {
    "path": "src/algorithms/math/horner-method/__test__/classicPolynome.test.js",
    "content": "import classicPolynome from '../classicPolynome';\n\ndescribe('classicPolynome', () => {\n  it('should evaluate the polynomial for the specified value of x correctly', () => {\n    expect(classicPolynome([8], 0.1)).toBe(8);\n    expect(classicPolynome([2, 4, 2, 5], 0.555)).toBe(7.68400775);\n    expect(classicPolynome([2, 4, 2, 5], 0.75)).toBe(9.59375);\n    expect(classicPolynome([1, 1, 1, 1, 1], 1.75)).toBe(20.55078125);\n    expect(classicPolynome([15, 3.5, 0, 2, 1.42, 0.41], 0.315)).toBe(1.1367300651406251);\n    expect(classicPolynome([0, 0, 2.77, 1.42, 0.41], 1.35)).toBe(7.375325000000001);\n    expect(classicPolynome([0, 0, 2.77, 1.42, 2.3311], 1.35)).toBe(9.296425000000001);\n    expect(classicPolynome([2, 0, 0, 5.757, 5.31412, 12.3213], 3.141)).toBe(697.2731167035034);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/horner-method/__test__/hornerMethod.test.js",
    "content": "import hornerMethod from '../hornerMethod';\nimport classicPolynome from '../classicPolynome';\n\ndescribe('hornerMethod', () => {\n  it('should evaluate the polynomial for the specified value of x correctly', () => {\n    expect(hornerMethod([8], 0.1)).toBe(8);\n    expect(hornerMethod([2, 4, 2, 5], 0.555)).toBe(7.68400775);\n    expect(hornerMethod([2, 4, 2, 5], 0.75)).toBe(9.59375);\n    expect(hornerMethod([1, 1, 1, 1, 1], 1.75)).toBe(20.55078125);\n    expect(hornerMethod([15, 3.5, 0, 2, 1.42, 0.41], 0.315)).toBe(1.136730065140625);\n    expect(hornerMethod([0, 0, 2.77, 1.42, 0.41], 1.35)).toBe(7.375325000000001);\n    expect(hornerMethod([0, 0, 2.77, 1.42, 2.3311], 1.35)).toBe(9.296425000000001);\n    expect(hornerMethod([2, 0, 0, 5.757, 5.31412, 12.3213], 3.141)).toBe(697.2731167035034);\n  });\n\n  it('should evaluate the same polynomial value as classical approach', () => {\n    expect(hornerMethod([8], 0.1)).toBe(classicPolynome([8], 0.1));\n    expect(hornerMethod([2, 4, 2, 5], 0.555)).toBe(classicPolynome([2, 4, 2, 5], 0.555));\n    expect(hornerMethod([2, 4, 2, 5], 0.75)).toBe(classicPolynome([2, 4, 2, 5], 0.75));\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/horner-method/classicPolynome.js",
    "content": "/**\n * Returns the evaluation of a polynomial function at a certain point.\n * Uses straightforward approach with powers.\n *\n * @param {number[]} coefficients - i.e. [4, 3, 2] for (4 * x^2 + 3 * x + 2)\n * @param {number} xVal\n * @return {number}\n */\nexport default function classicPolynome(coefficients, xVal) {\n  return coefficients.reverse().reduce(\n    (accumulator, currentCoefficient, index) => {\n      return accumulator + currentCoefficient * (xVal ** index);\n    },\n    0,\n  );\n}\n"
  },
  {
    "path": "src/algorithms/math/horner-method/hornerMethod.js",
    "content": "/**\n * Returns the evaluation of a polynomial function at a certain point.\n * Uses Horner's rule.\n *\n * @param {number[]} coefficients - i.e. [4, 3, 2] for (4 * x^2 + 3 * x + 2)\n * @param {number} xVal\n * @return {number}\n */\nexport default function hornerMethod(coefficients, xVal) {\n  return coefficients.reduce(\n    (accumulator, currentCoefficient) => {\n      return accumulator * xVal + currentCoefficient;\n    },\n    0,\n  );\n}\n"
  },
  {
    "path": "src/algorithms/math/integer-partition/README.md",
    "content": "# Integer Partition\n\nIn number theory and combinatorics, a partition of a positive \ninteger `n`, also called an **integer partition**, is a way of \nwriting `n` as a sum of positive integers. \n\nTwo sums that differ only in the order of their summands are \nconsidered the same partition. For example, `4` can be partitioned \nin five distinct ways:\n\n```\n4\n3 + 1\n2 + 2\n2 + 1 + 1\n1 + 1 + 1 + 1\n```\n\nThe order-dependent composition `1 + 3` is the same partition\nas `3 + 1`, while the two distinct \ncompositions `1 + 2 + 1` and `1 + 1 + 2` represent the same \npartition `2 + 1 + 1`.\n\nYoung diagrams associated to the partitions of the positive\nintegers `1` through `8`. They are arranged so that images \nunder the reflection about the main diagonal of the square \nare conjugate partitions.\n\n![Integer Partition](https://upload.wikimedia.org/wikipedia/commons/d/d8/Ferrer_partitioning_diagrams.svg)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Partition_(number_theory))\n- [YouTube](https://www.youtube.com/watch?v=ZaVM057DuzE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/math/integer-partition/__test__/integerPartition.test.js",
    "content": "import integerPartition from '../integerPartition';\n\ndescribe('integerPartition', () => {\n  it('should partition the number', () => {\n    expect(integerPartition(1)).toBe(1);\n    expect(integerPartition(2)).toBe(2);\n    expect(integerPartition(3)).toBe(3);\n    expect(integerPartition(4)).toBe(5);\n    expect(integerPartition(5)).toBe(7);\n    expect(integerPartition(6)).toBe(11);\n    expect(integerPartition(7)).toBe(15);\n    expect(integerPartition(8)).toBe(22);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/integer-partition/integerPartition.js",
    "content": "/**\n * @param {number} number\n * @return {number}\n */\nexport default function integerPartition(number) {\n  // Create partition matrix for solving this task using Dynamic Programming.\n  const partitionMatrix = Array(number + 1).fill(null).map(() => {\n    return Array(number + 1).fill(null);\n  });\n\n  // Fill partition matrix with initial values.\n\n  // Let's fill the first row that represents how many ways we would have\n  // to combine the numbers 1, 2, 3, ..., n with number 0. We would have zero\n  // ways obviously since with zero number we may form only zero.\n  for (let numberIndex = 1; numberIndex <= number; numberIndex += 1) {\n    partitionMatrix[0][numberIndex] = 0;\n  }\n\n  // Let's fill the first column. It represents the number of ways we can form\n  // number zero out of numbers 0, 0 and 1, 0 and 1 and 2, 0 and 1 and 2 and 3, ...\n  // Obviously there is only one way we could form number 0\n  // and it is with number 0 itself.\n  for (let summandIndex = 0; summandIndex <= number; summandIndex += 1) {\n    partitionMatrix[summandIndex][0] = 1;\n  }\n\n  // Now let's go through other possible options of how we could form number m out of\n  // summands 0, 1, ..., m using Dynamic Programming approach.\n  for (let summandIndex = 1; summandIndex <= number; summandIndex += 1) {\n    for (let numberIndex = 1; numberIndex <= number; numberIndex += 1) {\n      if (summandIndex > numberIndex) {\n        // If summand number is bigger then current number itself then just it won't add\n        // any new ways of forming the number. Thus we may just copy the number from row above.\n        partitionMatrix[summandIndex][numberIndex] = partitionMatrix[summandIndex - 1][numberIndex];\n      } else {\n        /*\n         * The number of combinations would equal to number of combinations of forming the same\n         * number but WITHOUT current summand number PLUS number of combinations of forming the\n         * <current number - current summand> number but WITH current summand.\n         *\n         * Example:\n         * Number of ways to form 5 using summands {0, 1, 2} would equal the SUM of:\n         * - number of ways to form 5 using summands {0, 1} (we've excluded summand 2)\n         * - number of ways to form 3 (because 5 - 2 = 3) using summands {0, 1, 2}\n         * (we've included summand 2)\n        */\n        const combosWithoutSummand = partitionMatrix[summandIndex - 1][numberIndex];\n        const combosWithSummand = partitionMatrix[summandIndex][numberIndex - summandIndex];\n\n        partitionMatrix[summandIndex][numberIndex] = combosWithoutSummand + combosWithSummand;\n      }\n    }\n  }\n\n  return partitionMatrix[number][number];\n}\n"
  },
  {
    "path": "src/algorithms/math/is-power-of-two/README.md",
    "content": "# Is a power of two\n\nGiven a positive integer, write a function to find if it is\na power of two or not.\n\n**Naive solution**\n\nIn naive solution we just keep dividing the number by two\nunless the number becomes `1` and every time we do so, we\ncheck that remainder after division is always `0`. Otherwise, the number can't be a power of two.\n\n**Bitwise solution**\n\nPowers of two in binary form always have just one bit set.\nThe only exception is with a signed integer (e.g. an 8-bit\nsigned integer with a value of -128 looks like: `10000000`)\n\n```\n1: 0001\n2: 0010\n4: 0100\n8: 1000\n```\n\nSo after checking that the number is greater than zero,\nwe can use a bitwise hack to test that one and only one\nbit is set.\n\n```\nnumber & (number - 1)\n```\n\nFor example for number `8` that operations will look like:\n\n```\n  1000\n- 0001\n  ----\n  0111\n\n  1000\n& 0111\n  ----\n  0000\n```\n\n## References\n\n- [GeeksForGeeks](https://www.geeksforgeeks.org/program-to-find-whether-a-no-is-power-of-two/)\n- [Bitwise Solution on Stanford](http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)\n- [Binary number subtraction on YouTube](https://www.youtube.com/watch?v=S9LJknZTyos&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=66)\n"
  },
  {
    "path": "src/algorithms/math/is-power-of-two/__test__/isPowerOfTwo.test.js",
    "content": "import isPowerOfTwo from '../isPowerOfTwo';\n\ndescribe('isPowerOfTwo', () => {\n  it('should check if the number is made by multiplying twos', () => {\n    expect(isPowerOfTwo(-1)).toBe(false);\n    expect(isPowerOfTwo(0)).toBe(false);\n    expect(isPowerOfTwo(1)).toBe(true);\n    expect(isPowerOfTwo(2)).toBe(true);\n    expect(isPowerOfTwo(3)).toBe(false);\n    expect(isPowerOfTwo(4)).toBe(true);\n    expect(isPowerOfTwo(5)).toBe(false);\n    expect(isPowerOfTwo(6)).toBe(false);\n    expect(isPowerOfTwo(7)).toBe(false);\n    expect(isPowerOfTwo(8)).toBe(true);\n    expect(isPowerOfTwo(10)).toBe(false);\n    expect(isPowerOfTwo(12)).toBe(false);\n    expect(isPowerOfTwo(16)).toBe(true);\n    expect(isPowerOfTwo(31)).toBe(false);\n    expect(isPowerOfTwo(64)).toBe(true);\n    expect(isPowerOfTwo(1024)).toBe(true);\n    expect(isPowerOfTwo(1023)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/is-power-of-two/__test__/isPowerOfTwoBitwise.test.js",
    "content": "import isPowerOfTwoBitwise from '../isPowerOfTwoBitwise';\n\ndescribe('isPowerOfTwoBitwise', () => {\n  it('should check if the number is made by multiplying twos', () => {\n    expect(isPowerOfTwoBitwise(-1)).toBe(false);\n    expect(isPowerOfTwoBitwise(0)).toBe(false);\n    expect(isPowerOfTwoBitwise(1)).toBe(true);\n    expect(isPowerOfTwoBitwise(2)).toBe(true);\n    expect(isPowerOfTwoBitwise(3)).toBe(false);\n    expect(isPowerOfTwoBitwise(4)).toBe(true);\n    expect(isPowerOfTwoBitwise(5)).toBe(false);\n    expect(isPowerOfTwoBitwise(6)).toBe(false);\n    expect(isPowerOfTwoBitwise(7)).toBe(false);\n    expect(isPowerOfTwoBitwise(8)).toBe(true);\n    expect(isPowerOfTwoBitwise(10)).toBe(false);\n    expect(isPowerOfTwoBitwise(12)).toBe(false);\n    expect(isPowerOfTwoBitwise(16)).toBe(true);\n    expect(isPowerOfTwoBitwise(31)).toBe(false);\n    expect(isPowerOfTwoBitwise(64)).toBe(true);\n    expect(isPowerOfTwoBitwise(1024)).toBe(true);\n    expect(isPowerOfTwoBitwise(1023)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/is-power-of-two/isPowerOfTwo.js",
    "content": "/**\n * @param {number} number\n * @return {boolean}\n */\nexport default function isPowerOfTwo(number) {\n  // 1 (2^0) is the smallest power of two.\n  if (number < 1) {\n    return false;\n  }\n\n  // Let's find out if we can divide the number by two\n  // many times without remainder.\n  let dividedNumber = number;\n  while (dividedNumber !== 1) {\n    if (dividedNumber % 2 !== 0) {\n      // For every case when remainder isn't zero we can say that this number\n      // couldn't be a result of power of two.\n      return false;\n    }\n\n    dividedNumber /= 2;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "src/algorithms/math/is-power-of-two/isPowerOfTwoBitwise.js",
    "content": "/**\n * @param {number} number\n * @return {boolean}\n */\nexport default function isPowerOfTwoBitwise(number) {\n  // 1 (2^0) is the smallest power of two.\n  if (number < 1) {\n    return false;\n  }\n\n  /*\n   * Powers of two in binary look like this:\n   * 1: 0001\n   * 2: 0010\n   * 4: 0100\n   * 8: 1000\n   *\n   * Note that there is always exactly 1 bit set. The only exception is with a signed integer.\n   * e.g. An 8-bit signed integer with a value of -128 looks like:\n   * 10000000\n   *\n   * So after checking that the number is greater than zero, we can use a clever little bit\n   * hack to test that one and only one bit is set.\n   */\n  return (number & (number - 1)) === 0;\n}\n"
  },
  {
    "path": "src/algorithms/math/least-common-multiple/README.md",
    "content": "# Least common multiple\n\nIn arithmetic and number theory, the least common multiple, \nlowest common multiple, or smallest common multiple of \ntwo integers `a` and `b`, usually denoted by `LCM(a, b)`, is \nthe smallest positive integer that is divisible by \nboth `a` and `b`. Since division of integers by zero is \nundefined, this definition has meaning only if `a` and `b` are \nboth different from zero. However, some authors define `lcm(a,0)`\nas `0` for all `a`, which is the result of taking the `lcm`\nto be the least upper bound in the lattice of divisibility.\n\n## Example\n\nWhat is the LCM of 4 and 6?\n\nMultiples of `4` are:\n\n```\n4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, ...\n```\n\nand the multiples of `6` are:\n\n```\n6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, ...\n```\n\nCommon multiples of `4` and `6` are simply the numbers \nthat are in both lists:\n\n```\n12, 24, 36, 48, 60, 72, ....\n```\n\nSo, from this list of the first few common multiples of \nthe numbers `4` and `6`, their least common multiple is `12`.\n\n## Computing the least common multiple\n\nThe following formula reduces the problem of computing the \nleast common multiple to the problem of computing the greatest \ncommon divisor (GCD), also known as the greatest common factor:\n\n```\nlcm(a, b) = |a * b| / gcd(a, b)\n```\n\n![LCM](https://upload.wikimedia.org/wikipedia/commons/c/c9/Symmetrical_5-set_Venn_diagram_LCM_2_3_4_5_7.svg)\n\nA Venn diagram showing the least common multiples of \ncombinations of `2`, `3`, `4`, `5` and `7` (`6` is skipped as \nit is `2 × 3`, both of which are already represented).\n\nFor example, a card game which requires its cards to be \ndivided equally among up to `5` players requires at least `60`\ncards, the number at the intersection of the `2`, `3`, `4`\nand `5` sets, but not the `7` set.\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Least_common_multiple)\n"
  },
  {
    "path": "src/algorithms/math/least-common-multiple/__test__/leastCommonMultiple.test.js",
    "content": "import leastCommonMultiple from '../leastCommonMultiple';\n\ndescribe('leastCommonMultiple', () => {\n  it('should find least common multiple', () => {\n    expect(leastCommonMultiple(0, 0)).toBe(0);\n    expect(leastCommonMultiple(1, 0)).toBe(0);\n    expect(leastCommonMultiple(0, 1)).toBe(0);\n    expect(leastCommonMultiple(4, 6)).toBe(12);\n    expect(leastCommonMultiple(6, 21)).toBe(42);\n    expect(leastCommonMultiple(7, 2)).toBe(14);\n    expect(leastCommonMultiple(3, 5)).toBe(15);\n    expect(leastCommonMultiple(7, 3)).toBe(21);\n    expect(leastCommonMultiple(1000000, 2)).toBe(1000000);\n    expect(leastCommonMultiple(-9, -18)).toBe(18);\n    expect(leastCommonMultiple(-7, -9)).toBe(63);\n    expect(leastCommonMultiple(-7, 9)).toBe(63);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/least-common-multiple/leastCommonMultiple.js",
    "content": "import euclideanAlgorithm from '../euclidean-algorithm/euclideanAlgorithm';\n\n/**\n * @param {number} a\n * @param {number} b\n * @return {number}\n */\n\nexport default function leastCommonMultiple(a, b) {\n  return ((a === 0) || (b === 0)) ? 0 : Math.abs(a * b) / euclideanAlgorithm(a, b);\n}\n"
  },
  {
    "path": "src/algorithms/math/liu-hui/README.md",
    "content": "# Liu Hui's π Algorithm\n\nLiu Hui remarked in his commentary to The Nine Chapters on the Mathematical Art,\nthat the ratio of the circumference of an inscribed hexagon to the diameter of \nthe circle was `three`, hence `π` must be greater than three. He went on to provide \na detailed step-by-step description of an iterative algorithm to calculate `π` to \nany required accuracy based on bisecting polygons; he calculated `π` to \nbetween `3.141024` and `3.142708` with a 96-gon; he suggested that `3.14` was \na good enough approximation, and expressed `π` as `157/50`; he admitted that \nthis number was a bit small. Later he invented an ingenious quick method to \nimprove on it, and obtained `π ≈ 3.1416` with only a 96-gon, with an accuracy \ncomparable to that from a 1536-gon. His most important contribution in this \narea was his simple iterative `π` algorithm.\n\n## Area of a circle\n\nLiu Hui argued:\n\n> Multiply one side of a hexagon by the radius (of its \ncircumcircle), then multiply this by three, to yield the \narea of a dodecagon; if we cut a hexagon into a \ndodecagon, multiply its side by its radius, then again \nmultiply by six, we get the area of a 24-gon; the finer \nwe cut, the smaller the loss with respect to the area \nof circle, thus with further cut after cut, the area of \nthe resulting polygon will coincide and become one with \nthe circle; there will be no loss\n\n![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/6/69/Cutcircle2.svg)\n\nLiu Hui's method of calculating the area of a circle.\n\nFurther, Liu Hui proved that the area of a circle is half of its circumference \nmultiplied by its radius. He said:\n\n> Between a polygon and a circle, there is excess radius. Multiply the excess \nradius by a side of the polygon. The resulting area exceeds the boundary of \nthe circle\n\nIn the diagram `d = excess radius`. Multiplying `d` by one side results in \noblong `ABCD` which exceeds the boundary of the circle. If a side of the polygon \nis small (i.e. there is a very large number of sides), then the excess radius \nwill be small, hence excess area will be small.\n\n> Multiply the side of a polygon by its radius, and the area doubles; \nhence multiply half the circumference by the radius to yield the area of circle.\n\n![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/9/95/Cutcircle.svg)\n\nThe area within a circle is equal to the radius multiplied by half the \ncircumference, or `A = r x C/2 = r x r x π`.\n\n## Iterative algorithm\n\nLiu Hui began with an inscribed hexagon. Let `M` be the length of one side `AB` of \nhexagon, `r` is the radius of circle.\n\n![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/4/46/Liuhui_geyuanshu.svg)\n\nBisect `AB` with line `OPC`, `AC` becomes one side of dodecagon (12-gon), let \nits length be `m`. Let the length of `PC` be `j` and the length of `OP` be `G`.\n\n`AOP`, `APC` are two right angle triangles. Liu Hui used \nthe [Gou Gu](https://en.wikipedia.org/wiki/Pythagorean_theorem) (Pythagorean theorem)\ntheorem repetitively:\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/dbfc192c78539c3901c7bad470302ededb76f813)\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/ccd12a402367c2d6614c88e75006d50bfc3a9929)\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/65d77869fc02c302d2d46d45f75ad7e79ae524fb)\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/a7a0d0d7f505a0f434e5dd80c2fef6d2b30d6100)\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/c31b9acf38f9d1a248d4023c3bf286bd03007f37)\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/0dee798efb0b1e3e64d6b3542106cb3ecaa4a383)\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/3ffeafe88d2983b364ad3442746063e3207fe842)\n\n\nFrom here, there is now a technique to determine `m` from `M`, which gives the \nside length for a polygon with twice the number of edges. Starting with a \nhexagon, Liu Hui could determine the side length of a dodecagon using this \nformula. Then continue repetitively to determine the side length of a \n24-gon given the side length of a dodecagon. He could do this recursively as \nmany times as necessary. Knowing how to determine the area of these polygons, \nLiu Hui could then approximate `π`.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Liu_Hui%27s_%CF%80_algorithm)\n"
  },
  {
    "path": "src/algorithms/math/liu-hui/__test__/liuHui.test.js",
    "content": "import liuHui from '../liuHui';\n\ndescribe('liuHui', () => {\n  it('should calculate π based on 12-gon', () => {\n    expect(liuHui(1)).toBe(3);\n  });\n\n  it('should calculate π based on 24-gon', () => {\n    expect(liuHui(2)).toBe(3.105828541230249);\n  });\n\n  it('should calculate π based on 6144-gon', () => {\n    expect(liuHui(10)).toBe(3.1415921059992717);\n  });\n\n  it('should calculate π based on 201326592-gon', () => {\n    expect(liuHui(25)).toBe(3.141592653589793);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/liu-hui/liuHui.js",
    "content": "/*\n * Let circleRadius is the radius of circle.\n * circleRadius is also the side length of the inscribed hexagon\n */\nconst circleRadius = 1;\n\n/**\n * @param {number} sideLength\n * @param {number} splitCounter\n * @return {number}\n */\nfunction getNGonSideLength(sideLength, splitCounter) {\n  if (splitCounter <= 0) {\n    return sideLength;\n  }\n\n  const halfSide = sideLength / 2;\n\n  // Liu Hui used the Gou Gu (Pythagorean theorem) theorem repetitively.\n  const perpendicular = Math.sqrt((circleRadius ** 2) - (halfSide ** 2));\n  const excessRadius = circleRadius - perpendicular;\n  const splitSideLength = Math.sqrt((excessRadius ** 2) + (halfSide ** 2));\n\n  return getNGonSideLength(splitSideLength, splitCounter - 1);\n}\n\n/**\n * @param {number} splitCount\n * @return {number}\n */\nfunction getNGonSideCount(splitCount) {\n  // Liu Hui began with an inscribed hexagon (6-gon).\n  const hexagonSidesCount = 6;\n\n  // On every split iteration we make N-gons: 6-gon, 12-gon, 24-gon, 48-gon and so on.\n  return hexagonSidesCount * (splitCount ? 2 ** splitCount : 1);\n}\n\n/**\n * Calculate the π value using Liu Hui's π algorithm\n *\n * @param {number} splitCount - number of times we're going to split 6-gon.\n *  On each split we will receive 12-gon, 24-gon and so on.\n * @return {number}\n */\nexport default function liuHui(splitCount = 1) {\n  const nGonSideLength = getNGonSideLength(circleRadius, splitCount - 1);\n  const nGonSideCount = getNGonSideCount(splitCount - 1);\n  const nGonPerimeter = nGonSideLength * nGonSideCount;\n  const approximateCircleArea = (nGonPerimeter / 2) * circleRadius;\n\n  // Return approximate value of pi.\n  return approximateCircleArea / (circleRadius ** 2);\n}\n"
  },
  {
    "path": "src/algorithms/math/matrix/Matrix.js",
    "content": "/**\n * @typedef {number} Cell\n * @typedef {Cell[][]|Cell[][][]} Matrix\n * @typedef {number[]} Shape\n * @typedef {number[]} CellIndices\n */\n\n/**\n * Gets the matrix's shape.\n *\n * @param {Matrix} m\n * @returns {Shape}\n */\nexport const shape = (m) => {\n  const shapes = [];\n  let dimension = m;\n  while (dimension && Array.isArray(dimension)) {\n    shapes.push(dimension.length);\n    dimension = (dimension.length && [...dimension][0]) || null;\n  }\n  return shapes;\n};\n\n/**\n * Checks if matrix has a correct type.\n *\n * @param {Matrix} m\n * @throws {Error}\n */\nconst validateType = (m) => {\n  if (\n    !m\n    || !Array.isArray(m)\n    || !Array.isArray(m[0])\n  ) {\n    throw new Error('Invalid matrix format');\n  }\n};\n\n/**\n * Checks if matrix is two dimensional.\n *\n * @param {Matrix} m\n * @throws {Error}\n */\nconst validate2D = (m) => {\n  validateType(m);\n  const aShape = shape(m);\n  if (aShape.length !== 2) {\n    throw new Error('Matrix is not of 2D shape');\n  }\n};\n\n/**\n * Validates that matrices are of the same shape.\n *\n * @param {Matrix} a\n * @param {Matrix} b\n * @trows {Error}\n */\nexport const validateSameShape = (a, b) => {\n  validateType(a);\n  validateType(b);\n\n  const aShape = shape(a);\n  const bShape = shape(b);\n\n  if (aShape.length !== bShape.length) {\n    throw new Error('Matrices have different dimensions');\n  }\n\n  while (aShape.length && bShape.length) {\n    if (aShape.pop() !== bShape.pop()) {\n      throw new Error('Matrices have different shapes');\n    }\n  }\n};\n\n/**\n * Generates the matrix of specific shape with specific values.\n *\n * @param {Shape} mShape - the shape of the matrix to generate\n * @param {function({CellIndex}): Cell} fill - cell values of a generated matrix.\n * @returns {Matrix}\n */\nexport const generate = (mShape, fill) => {\n  /**\n   * Generates the matrix recursively.\n   *\n   * @param {Shape} recShape - the shape of the matrix to generate\n   * @param {CellIndices} recIndices\n   * @returns {Matrix}\n   */\n  const generateRecursively = (recShape, recIndices) => {\n    if (recShape.length === 1) {\n      return Array(recShape[0])\n        .fill(null)\n        .map((cellValue, cellIndex) => fill([...recIndices, cellIndex]));\n    }\n    const m = [];\n    for (let i = 0; i < recShape[0]; i += 1) {\n      m.push(generateRecursively(recShape.slice(1), [...recIndices, i]));\n    }\n    return m;\n  };\n\n  return generateRecursively(mShape, []);\n};\n\n/**\n * Generates the matrix of zeros of specified shape.\n *\n * @param {Shape} mShape - shape of the matrix\n * @returns {Matrix}\n */\nexport const zeros = (mShape) => {\n  return generate(mShape, () => 0);\n};\n\n/**\n * @param {Matrix} a\n * @param {Matrix} b\n * @return Matrix\n * @throws {Error}\n */\nexport const dot = (a, b) => {\n  // Validate inputs.\n  validate2D(a);\n  validate2D(b);\n\n  // Check dimensions.\n  const aShape = shape(a);\n  const bShape = shape(b);\n  if (aShape[1] !== bShape[0]) {\n    throw new Error('Matrices have incompatible shape for multiplication');\n  }\n\n  // Perform matrix multiplication.\n  const outputShape = [aShape[0], bShape[1]];\n  const c = zeros(outputShape);\n\n  for (let bCol = 0; bCol < b[0].length; bCol += 1) {\n    for (let aRow = 0; aRow < a.length; aRow += 1) {\n      let cellSum = 0;\n      for (let aCol = 0; aCol < a[aRow].length; aCol += 1) {\n        cellSum += a[aRow][aCol] * b[aCol][bCol];\n      }\n      c[aRow][bCol] = cellSum;\n    }\n  }\n\n  return c;\n};\n\n/**\n * Transposes the matrix.\n *\n * @param {Matrix} m\n * @returns Matrix\n * @throws {Error}\n */\nexport const t = (m) => {\n  validate2D(m);\n  const mShape = shape(m);\n  const transposed = zeros([mShape[1], mShape[0]]);\n  for (let row = 0; row < m.length; row += 1) {\n    for (let col = 0; col < m[0].length; col += 1) {\n      transposed[col][row] = m[row][col];\n    }\n  }\n  return transposed;\n};\n\n/**\n * Traverses the matrix.\n *\n * @param {Matrix} m\n * @param {function(indices: CellIndices, c: Cell)} visit\n */\nexport const walk = (m, visit) => {\n  /**\n   * Traverses the matrix recursively.\n   *\n   * @param {Matrix} recM\n   * @param {CellIndices} cellIndices\n   * @return {Matrix}\n   */\n  const recWalk = (recM, cellIndices) => {\n    const recMShape = shape(recM);\n\n    if (recMShape.length === 1) {\n      for (let i = 0; i < recM.length; i += 1) {\n        visit([...cellIndices, i], recM[i]);\n      }\n    }\n    for (let i = 0; i < recM.length; i += 1) {\n      recWalk(recM[i], [...cellIndices, i]);\n    }\n  };\n\n  recWalk(m, []);\n};\n\n/**\n * Gets the matrix cell value at specific index.\n *\n * @param {Matrix} m - Matrix that contains the cell that needs to be updated\n * @param {CellIndices} cellIndices - Array of cell indices\n * @return {Cell}\n */\nexport const getCellAtIndex = (m, cellIndices) => {\n  // We start from the row at specific index.\n  let cell = m[cellIndices[0]];\n  // Going deeper into the next dimensions but not to the last one to preserve\n  // the pointer to the last dimension array.\n  for (let dimIdx = 1; dimIdx < cellIndices.length - 1; dimIdx += 1) {\n    cell = cell[cellIndices[dimIdx]];\n  }\n  // At this moment the cell variable points to the array at the last needed dimension.\n  return cell[cellIndices[cellIndices.length - 1]];\n};\n\n/**\n * Update the matrix cell at specific index.\n *\n * @param {Matrix} m - Matrix that contains the cell that needs to be updated\n * @param {CellIndices} cellIndices - Array of cell indices\n * @param {Cell} cellValue - New cell value\n */\nexport const updateCellAtIndex = (m, cellIndices, cellValue) => {\n  // We start from the row at specific index.\n  let cell = m[cellIndices[0]];\n  // Going deeper into the next dimensions but not to the last one to preserve\n  // the pointer to the last dimension array.\n  for (let dimIdx = 1; dimIdx < cellIndices.length - 1; dimIdx += 1) {\n    cell = cell[cellIndices[dimIdx]];\n  }\n  // At this moment the cell variable points to the array at the last needed dimension.\n  cell[cellIndices[cellIndices.length - 1]] = cellValue;\n};\n\n/**\n * Adds two matrices element-wise.\n *\n * @param {Matrix} a\n * @param {Matrix} b\n * @return {Matrix}\n */\nexport const add = (a, b) => {\n  validateSameShape(a, b);\n  const result = zeros(shape(a));\n\n  walk(a, (cellIndices, cellValue) => {\n    updateCellAtIndex(result, cellIndices, cellValue);\n  });\n\n  walk(b, (cellIndices, cellValue) => {\n    const currentCellValue = getCellAtIndex(result, cellIndices);\n    updateCellAtIndex(result, cellIndices, currentCellValue + cellValue);\n  });\n\n  return result;\n};\n\n/**\n * Multiplies two matrices element-wise.\n *\n * @param {Matrix} a\n * @param {Matrix} b\n * @return {Matrix}\n */\nexport const mul = (a, b) => {\n  validateSameShape(a, b);\n  const result = zeros(shape(a));\n\n  walk(a, (cellIndices, cellValue) => {\n    updateCellAtIndex(result, cellIndices, cellValue);\n  });\n\n  walk(b, (cellIndices, cellValue) => {\n    const currentCellValue = getCellAtIndex(result, cellIndices);\n    updateCellAtIndex(result, cellIndices, currentCellValue * cellValue);\n  });\n\n  return result;\n};\n\n/**\n * Subtract two matrices element-wise.\n *\n * @param {Matrix} a\n * @param {Matrix} b\n * @return {Matrix}\n */\nexport const sub = (a, b) => {\n  validateSameShape(a, b);\n  const result = zeros(shape(a));\n\n  walk(a, (cellIndices, cellValue) => {\n    updateCellAtIndex(result, cellIndices, cellValue);\n  });\n\n  walk(b, (cellIndices, cellValue) => {\n    const currentCellValue = getCellAtIndex(result, cellIndices);\n    updateCellAtIndex(result, cellIndices, currentCellValue - cellValue);\n  });\n\n  return result;\n};\n"
  },
  {
    "path": "src/algorithms/math/matrix/README.md",
    "content": "# Matrices\n\nIn 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:\n\n```\n| 1  9 -13 |\n| 20 5 -6  |\n```\n\n![An `m × n` matrix](https://upload.wikimedia.org/wikipedia/commons/b/bf/Matris.png)\n\nAn `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\n\n## Operations on matrices\n\n### Addition\n\nTo add two matrices: add the numbers in the matching positions:\n\n![Matrices addition](https://www.mathsisfun.com/algebra/images/matrix-addition.gif)\n\nThe two matrices must be the same size, i.e. the rows must match in size, and the columns must match in size.\n\n### Subtracting\n\nTo subtract two matrices: subtract the numbers in the matching positions:\n\n![Matrices subtraction](https://www.mathsisfun.com/algebra/images/matrix-subtraction.gif)\n\n### Multiply by a Constant\n\nWe can multiply a matrix by a constant (the value 2 in this case):\n\n![Matrices multiplication be a constant](https://www.mathsisfun.com/algebra/images/matrix-multiply-constant.gif)\n\n### Multiplying by Another Matrix\n\nTo 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.\n\nTo work out the answer for the **1st row** and **1st column**:\n\n![Matrices multiplication - 1st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-a.svg)\n\nHere it is for the 1st row and 2nd column:\n\n![Matrices multiplication - 2st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-b.svg)\n\nIf we'll do the same for the rest of the rows and columns we'll get the following resulting matrix:\n\n![Matrices multiplication - Result](https://www.mathsisfun.com/algebra/images/matrix-multiply-c.svg)\n\n### Transposing\n\nTo \"transpose\" a matrix, swap the rows and columns.\n\nWe put a \"T\" in the top right-hand corner to mean transpose:\n\n![Transposing](https://www.mathsisfun.com/algebra/images/matrix-transpose.gif)\n\n## References\n\n- [Matrices on MathIsFun](https://www.mathsisfun.com/algebra/matrix-introduction.html)\n- [Matrix on Wikipedia](https://en.wikipedia.org/wiki/Matrix_(mathematics))\n"
  },
  {
    "path": "src/algorithms/math/matrix/__tests__/Matrix.test.js",
    "content": "import * as mtrx from '../Matrix';\n\ndescribe('Matrix', () => {\n  it('should throw when trying to add matrices of invalid shapes', () => {\n    expect(\n      () => mtrx.dot([0], [1]),\n    ).toThrow('Invalid matrix format');\n    expect(\n      () => mtrx.dot([[0]], [1]),\n    ).toThrow('Invalid matrix format');\n    expect(\n      () => mtrx.dot([[[0]]], [[1]]),\n    ).toThrow('Matrix is not of 2D shape');\n    expect(\n      () => mtrx.dot([[0]], [[1], [2]]),\n    ).toThrow('Matrices have incompatible shape for multiplication');\n  });\n\n  it('should calculate matrices dimensions', () => {\n    expect(mtrx.shape([])).toEqual([0]);\n\n    expect(mtrx.shape([\n      [],\n    ])).toEqual([1, 0]);\n\n    expect(mtrx.shape([\n      [0],\n    ])).toEqual([1, 1]);\n\n    expect(mtrx.shape([\n      [0, 0],\n    ])).toEqual([1, 2]);\n\n    expect(mtrx.shape([\n      [0, 0],\n      [0, 0],\n    ])).toEqual([2, 2]);\n\n    expect(mtrx.shape([\n      [0, 0, 0],\n      [0, 0, 0],\n    ])).toEqual([2, 3]);\n\n    expect(mtrx.shape([\n      [0, 0],\n      [0, 0],\n      [0, 0],\n    ])).toEqual([3, 2]);\n\n    expect(mtrx.shape([\n      [0, 0, 0],\n      [0, 0, 0],\n      [0, 0, 0],\n    ])).toEqual([3, 3]);\n\n    expect(mtrx.shape([\n      [0],\n      [0],\n      [0],\n    ])).toEqual([3, 1]);\n\n    expect(mtrx.shape([\n      [[0], [0], [0]],\n      [[0], [0], [0]],\n      [[0], [0], [0]],\n    ])).toEqual([3, 3, 1]);\n\n    expect(mtrx.shape([\n      [[0, 0, 0], [0, 0, 0], [0, 0, 0]],\n      [[0, 0, 0], [0, 0, 0], [0, 0, 0]],\n      [[0, 0, 0], [0, 0, 0], [0, 0, 0]],\n    ])).toEqual([3, 3, 3]);\n  });\n\n  it('should generate the matrix of zeros', () => {\n    expect(mtrx.zeros([1, 0])).toEqual([\n      [],\n    ]);\n\n    expect(mtrx.zeros([1, 1])).toEqual([\n      [0],\n    ]);\n\n    expect(mtrx.zeros([1, 3])).toEqual([\n      [0, 0, 0],\n    ]);\n\n    expect(mtrx.zeros([3, 3])).toEqual([\n      [0, 0, 0],\n      [0, 0, 0],\n      [0, 0, 0],\n    ]);\n\n    expect(mtrx.zeros([3, 3, 1])).toEqual([\n      [[0], [0], [0]],\n      [[0], [0], [0]],\n      [[0], [0], [0]],\n    ]);\n  });\n\n  it('should generate the matrix with custom values', () => {\n    expect(mtrx.generate([1, 0], () => 1)).toEqual([\n      [],\n    ]);\n\n    expect(mtrx.generate([1, 1], () => 1)).toEqual([\n      [1],\n    ]);\n\n    expect(mtrx.generate([1, 3], () => 1)).toEqual([\n      [1, 1, 1],\n    ]);\n\n    expect(mtrx.generate([3, 3], () => 1)).toEqual([\n      [1, 1, 1],\n      [1, 1, 1],\n      [1, 1, 1],\n    ]);\n\n    expect(mtrx.generate([3, 3, 1], () => 1)).toEqual([\n      [[1], [1], [1]],\n      [[1], [1], [1]],\n      [[1], [1], [1]],\n    ]);\n  });\n\n  it('should generate a custom matrix based on specific cell indices', () => {\n    const indicesCallback = jest.fn((indices) => {\n      return indices[0] * 10 + indices[1];\n    });\n    const m = mtrx.generate([3, 3], indicesCallback);\n\n    expect(indicesCallback).toHaveBeenCalledTimes(3 * 3);\n    expect(indicesCallback.mock.calls[0][0]).toEqual([0, 0]);\n    expect(indicesCallback.mock.calls[1][0]).toEqual([0, 1]);\n    expect(indicesCallback.mock.calls[2][0]).toEqual([0, 2]);\n    expect(indicesCallback.mock.calls[3][0]).toEqual([1, 0]);\n    expect(indicesCallback.mock.calls[4][0]).toEqual([1, 1]);\n    expect(indicesCallback.mock.calls[5][0]).toEqual([1, 2]);\n    expect(indicesCallback.mock.calls[6][0]).toEqual([2, 0]);\n    expect(indicesCallback.mock.calls[7][0]).toEqual([2, 1]);\n    expect(indicesCallback.mock.calls[8][0]).toEqual([2, 2]);\n    expect(m).toEqual([\n      [0, 1, 2],\n      [10, 11, 12],\n      [20, 21, 22],\n    ]);\n  });\n\n  it('should multiply two matrices', () => {\n    let c;\n    c = mtrx.dot(\n      [\n        [1, 2],\n        [3, 4],\n      ],\n      [\n        [5, 6],\n        [7, 8],\n      ],\n    );\n    expect(mtrx.shape(c)).toEqual([2, 2]);\n    expect(c).toEqual([\n      [19, 22],\n      [43, 50],\n    ]);\n\n    c = mtrx.dot(\n      [\n        [1, 2],\n        [3, 4],\n      ],\n      [\n        [5],\n        [6],\n      ],\n    );\n    expect(mtrx.shape(c)).toEqual([2, 1]);\n    expect(c).toEqual([\n      [17],\n      [39],\n    ]);\n\n    c = mtrx.dot(\n      [\n        [1, 2, 3],\n        [4, 5, 6],\n      ],\n      [\n        [7, 8],\n        [9, 10],\n        [11, 12],\n      ],\n    );\n    expect(mtrx.shape(c)).toEqual([2, 2]);\n    expect(c).toEqual([\n      [58, 64],\n      [139, 154],\n    ]);\n\n    c = mtrx.dot(\n      [\n        [3, 4, 2],\n      ],\n      [\n        [13, 9, 7, 5],\n        [8, 7, 4, 6],\n        [6, 4, 0, 3],\n      ],\n    );\n    expect(mtrx.shape(c)).toEqual([1, 4]);\n    expect(c).toEqual([\n      [83, 63, 37, 45],\n    ]);\n  });\n\n  it('should transpose matrices', () => {\n    expect(mtrx.t([[1, 2, 3]])).toEqual([\n      [1],\n      [2],\n      [3],\n    ]);\n\n    expect(mtrx.t([\n      [1],\n      [2],\n      [3],\n    ])).toEqual([\n      [1, 2, 3],\n    ]);\n\n    expect(mtrx.t([\n      [1, 2, 3],\n      [4, 5, 6],\n    ])).toEqual([\n      [1, 4],\n      [2, 5],\n      [3, 6],\n    ]);\n\n    expect(mtrx.t([\n      [1, 2, 3],\n      [4, 5, 6],\n      [7, 8, 9],\n    ])).toEqual([\n      [1, 4, 7],\n      [2, 5, 8],\n      [3, 6, 9],\n    ]);\n  });\n\n  it('should throw when trying to transpose non 2D matrix', () => {\n    expect(() => {\n      mtrx.t([[[1]]]);\n    }).toThrow('Matrix is not of 2D shape');\n  });\n\n  it('should add two matrices', () => {\n    expect(mtrx.add([[1]], [[2]])).toEqual([[3]]);\n\n    expect(mtrx.add(\n      [[1, 2, 3]],\n      [[4, 5, 6]],\n    ))\n      .toEqual(\n        [[5, 7, 9]],\n      );\n\n    expect(mtrx.add(\n      [[1], [2], [3]],\n      [[4], [5], [6]],\n    ))\n      .toEqual(\n        [[5], [7], [9]],\n      );\n\n    expect(mtrx.add(\n      [\n        [1, 2, 3],\n        [4, 5, 6],\n        [7, 8, 9],\n      ],\n      [\n        [10, 11, 12],\n        [13, 14, 15],\n        [16, 17, 18],\n      ],\n    ))\n      .toEqual(\n        [\n          [11, 13, 15],\n          [17, 19, 21],\n          [23, 25, 27],\n        ],\n      );\n\n    expect(mtrx.add(\n      [\n        [[1], [2], [3]],\n        [[4], [5], [6]],\n        [[7], [8], [9]],\n      ],\n      [\n        [[10], [11], [12]],\n        [[13], [14], [15]],\n        [[16], [17], [18]],\n      ],\n    ))\n      .toEqual(\n        [\n          [[11], [13], [15]],\n          [[17], [19], [21]],\n          [[23], [25], [27]],\n        ],\n      );\n  });\n\n  it('should throw when trying to add matrices of different shape', () => {\n    expect(() => mtrx.add([[0]], [[[0]]])).toThrow(\n      'Matrices have different dimensions',\n    );\n\n    expect(() => mtrx.add([[0]], [[0, 0]])).toThrow(\n      'Matrices have different shapes',\n    );\n  });\n\n  it('should do element wise multiplication two matrices', () => {\n    expect(mtrx.mul([[2]], [[3]])).toEqual([[6]]);\n\n    expect(mtrx.mul(\n      [[1, 2, 3]],\n      [[4, 5, 6]],\n    ))\n      .toEqual(\n        [[4, 10, 18]],\n      );\n\n    expect(mtrx.mul(\n      [[1], [2], [3]],\n      [[4], [5], [6]],\n    ))\n      .toEqual(\n        [[4], [10], [18]],\n      );\n\n    expect(mtrx.mul(\n      [\n        [1, 2],\n        [3, 4],\n      ],\n      [\n        [5, 6],\n        [7, 8],\n      ],\n    ))\n      .toEqual(\n        [\n          [5, 12],\n          [21, 32],\n        ],\n      );\n\n    expect(mtrx.mul(\n      [\n        [[1], [2]],\n        [[3], [4]],\n      ],\n      [\n        [[5], [6]],\n        [[7], [8]],\n      ],\n    ))\n      .toEqual(\n        [\n          [[5], [12]],\n          [[21], [32]],\n        ],\n      );\n  });\n\n  it('should throw when trying to multiply matrices element-wise of different shape', () => {\n    expect(() => mtrx.mul([[0]], [[[0]]])).toThrow(\n      'Matrices have different dimensions',\n    );\n\n    expect(() => mtrx.mul([[0]], [[0, 0]])).toThrow(\n      'Matrices have different shapes',\n    );\n  });\n\n  it('should do element wise subtraction two matrices', () => {\n    expect(mtrx.sub([[3]], [[2]])).toEqual([[1]]);\n\n    expect(mtrx.sub(\n      [[10, 12, 14]],\n      [[4, 5, 6]],\n    ))\n      .toEqual(\n        [[6, 7, 8]],\n      );\n\n    expect(mtrx.sub(\n      [[[10], [12], [14]]],\n      [[[4], [5], [6]]],\n    ))\n      .toEqual(\n        [[[6], [7], [8]]],\n      );\n\n    expect(mtrx.sub(\n      [\n        [10, 20],\n        [30, 40],\n      ],\n      [\n        [5, 6],\n        [7, 8],\n      ],\n    ))\n      .toEqual(\n        [\n          [5, 14],\n          [23, 32],\n        ],\n      );\n\n    expect(mtrx.sub(\n      [\n        [[10], [20]],\n        [[30], [40]],\n      ],\n      [\n        [[5], [6]],\n        [[7], [8]],\n      ],\n    ))\n      .toEqual(\n        [\n          [[5], [14]],\n          [[23], [32]],\n        ],\n      );\n  });\n\n  it('should throw when trying to subtract matrices element-wise of different shape', () => {\n    expect(() => mtrx.sub([[0]], [[[0]]])).toThrow(\n      'Matrices have different dimensions',\n    );\n\n    expect(() => mtrx.sub([[0]], [[0, 0]])).toThrow(\n      'Matrices have different shapes',\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/pascal-triangle/README.md",
    "content": "# Pascal's Triangle\n\nIn mathematics, **Pascal's triangle** is a triangular array of \nthe [binomial coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient).\n\nThe rows of Pascal's triangle are conventionally enumerated \nstarting with row `n = 0` at the top (the `0th` row). The \nentries in each row are numbered from the left beginning \nwith `k = 0` and are usually staggered relative to the \nnumbers in the adjacent rows. The triangle may be constructed\nin the following manner: In row `0` (the topmost row), there \nis a unique nonzero entry `1`. Each entry of each subsequent\nrow is constructed by adding the number above and to the \nleft with the number above and to the right, treating blank \nentries as `0`. For example, the initial number in the \nfirst (or any other) row is `1` (the sum of `0` and `1`),\nwhereas the numbers `1` and `3` in the third row are added \nto produce the number `4` in the fourth row.\n\n![Pascal's Triangle](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif)\n\n## Formula\n\nThe entry in the `nth` row and `kth` column of Pascal's \ntriangle is denoted ![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/206415d3742167e319b2e52c2ca7563b799abad7).\nFor example, the unique nonzero entry in the topmost \nrow is ![Formula example](https://wikimedia.org/api/rest_v1/media/math/render/svg/b7e35f86368d5978b46c07fd6dddca86bd6e635c).\n\nWith this notation, the construction of the previous \nparagraph may be written as follows:\n\n![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/203b128a098e18cbb8cf36d004bd7282b28461bf)\n\nfor any non-negative integer `n` and any \ninteger `k` between `0` and `n`, inclusive.\n\n![Binomial Coefficient](https://wikimedia.org/api/rest_v1/media/math/render/svg/a2457a7ef3c77831e34e06a1fe17a80b84a03181)\n\n## Calculating triangle entries in O(n) time\n\nWe know that `i`-th entry in a line number `lineNumber` is \nBinomial Coefficient `C(lineNumber, i)` and all lines start \nwith value `1`. The idea is to \ncalculate `C(lineNumber, i)` using `C(lineNumber, i-1)`. It \ncan be calculated in `O(1)` time using the following:\n\n```\nC(lineNumber, i)   = lineNumber! / ((lineNumber - i)! * i!)\nC(lineNumber, i - 1) = lineNumber! / ((lineNumber - i + 1)! * (i - 1)!)\n```\n\nWe can derive following expression from above two expressions:\n\n```\nC(lineNumber, i) = C(lineNumber, i - 1) * (lineNumber - i + 1) / i\n```\n\nSo `C(lineNumber, i)` can be calculated \nfrom `C(lineNumber, i - 1)` in `O(1)` time.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Pascal%27s_triangle)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/pascal-triangle/)\n"
  },
  {
    "path": "src/algorithms/math/pascal-triangle/__test__/pascalTriangle.test.js",
    "content": "import pascalTriangle from '../pascalTriangle';\n\ndescribe('pascalTriangle', () => {\n  it('should calculate Pascal Triangle coefficients for specific line number', () => {\n    expect(pascalTriangle(0)).toEqual([1]);\n    expect(pascalTriangle(1)).toEqual([1, 1]);\n    expect(pascalTriangle(2)).toEqual([1, 2, 1]);\n    expect(pascalTriangle(3)).toEqual([1, 3, 3, 1]);\n    expect(pascalTriangle(4)).toEqual([1, 4, 6, 4, 1]);\n    expect(pascalTriangle(5)).toEqual([1, 5, 10, 10, 5, 1]);\n    expect(pascalTriangle(6)).toEqual([1, 6, 15, 20, 15, 6, 1]);\n    expect(pascalTriangle(7)).toEqual([1, 7, 21, 35, 35, 21, 7, 1]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/pascal-triangle/__test__/pascalTriangleRecursive.test.js",
    "content": "import pascalTriangleRecursive from '../pascalTriangleRecursive';\n\ndescribe('pascalTriangleRecursive', () => {\n  it('should calculate Pascal Triangle coefficients for specific line number', () => {\n    expect(pascalTriangleRecursive(0)).toEqual([1]);\n    expect(pascalTriangleRecursive(1)).toEqual([1, 1]);\n    expect(pascalTriangleRecursive(2)).toEqual([1, 2, 1]);\n    expect(pascalTriangleRecursive(3)).toEqual([1, 3, 3, 1]);\n    expect(pascalTriangleRecursive(4)).toEqual([1, 4, 6, 4, 1]);\n    expect(pascalTriangleRecursive(5)).toEqual([1, 5, 10, 10, 5, 1]);\n    expect(pascalTriangleRecursive(6)).toEqual([1, 6, 15, 20, 15, 6, 1]);\n    expect(pascalTriangleRecursive(7)).toEqual([1, 7, 21, 35, 35, 21, 7, 1]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/pascal-triangle/pascalTriangle.js",
    "content": "/**\n * @param {number} lineNumber - zero based.\n * @return {number[]}\n */\nexport default function pascalTriangle(lineNumber) {\n  const currentLine = [1];\n\n  const currentLineSize = lineNumber + 1;\n\n  for (let numIndex = 1; numIndex < currentLineSize; numIndex += 1) {\n    // See explanation of this formula in README.\n    currentLine[numIndex] = (currentLine[numIndex - 1] * (lineNumber - numIndex + 1)) / numIndex;\n  }\n\n  return currentLine;\n}\n"
  },
  {
    "path": "src/algorithms/math/pascal-triangle/pascalTriangleRecursive.js",
    "content": "/**\n * @param {number} lineNumber - zero based.\n * @return {number[]}\n */\nexport default function pascalTriangleRecursive(lineNumber) {\n  if (lineNumber === 0) {\n    return [1];\n  }\n\n  const currentLineSize = lineNumber + 1;\n  const previousLineSize = currentLineSize - 1;\n\n  // Create container for current line values.\n  const currentLine = [];\n\n  // We'll calculate current line based on previous one.\n  const previousLine = pascalTriangleRecursive(lineNumber - 1);\n\n  // Let's go through all elements of current line except the first and\n  // last one (since they were and will be filled with 1's) and calculate\n  // current coefficient based on previous line.\n  for (let numIndex = 0; numIndex < currentLineSize; numIndex += 1) {\n    const leftCoefficient = (numIndex - 1) >= 0 ? previousLine[numIndex - 1] : 0;\n    const rightCoefficient = numIndex < previousLineSize ? previousLine[numIndex] : 0;\n\n    currentLine[numIndex] = leftCoefficient + rightCoefficient;\n  }\n\n  return currentLine;\n}\n"
  },
  {
    "path": "src/algorithms/math/primality-test/README.md",
    "content": "# Primality Test\n\nA **prime number** (or a **prime**) is a natural number greater than `1` that \ncannot be formed by multiplying two smaller natural numbers. A natural number \ngreater than `1` that is not prime is called a composite number. For \nexample, `5` is prime because the only ways of writing it as a \nproduct, `1 × 5` or `5 × 1`, involve `5` itself. However, `6` is \ncomposite because it is the product of two numbers `(2 × 3)` that are \nboth smaller than `6`. \n\n![Prime Numbers](https://upload.wikimedia.org/wikipedia/commons/f/f0/Primes-vs-composites.svg)\n\nA **primality test** is an algorithm for determining whether an input \nnumber is prime. Among other fields of mathematics, it is used \nfor cryptography. Unlike integer factorization, primality tests \ndo not generally give prime factors, only stating whether the \ninput number is prime or not. Factorization is thought to be \na computationally difficult problem, whereas primality testing \nis comparatively easy (its running time is polynomial in the \nsize of the input). \n\n## References\n\n- [Prime Numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)\n- [Primality Test on Wikipedia](https://en.wikipedia.org/wiki/Primality_test)\n"
  },
  {
    "path": "src/algorithms/math/primality-test/__test__/trialDivision.test.js",
    "content": "import trialDivision from '../trialDivision';\n\n/**\n * @param {function(n: number)} testFunction\n */\nfunction primalityTest(testFunction) {\n  expect(testFunction(1)).toBe(false);\n  expect(testFunction(2)).toBe(true);\n  expect(testFunction(3)).toBe(true);\n  expect(testFunction(5)).toBe(true);\n  expect(testFunction(11)).toBe(true);\n  expect(testFunction(191)).toBe(true);\n  expect(testFunction(191)).toBe(true);\n  expect(testFunction(199)).toBe(true);\n\n  expect(testFunction(-1)).toBe(false);\n  expect(testFunction(0)).toBe(false);\n  expect(testFunction(4)).toBe(false);\n  expect(testFunction(6)).toBe(false);\n  expect(testFunction(12)).toBe(false);\n  expect(testFunction(14)).toBe(false);\n  expect(testFunction(25)).toBe(false);\n  expect(testFunction(192)).toBe(false);\n  expect(testFunction(200)).toBe(false);\n  expect(testFunction(400)).toBe(false);\n\n  // It should also deal with floats.\n  expect(testFunction(0.5)).toBe(false);\n  expect(testFunction(1.3)).toBe(false);\n  expect(testFunction(10.5)).toBe(false);\n}\n\ndescribe('trialDivision', () => {\n  it('should detect prime numbers', () => {\n    primalityTest(trialDivision);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/primality-test/trialDivision.js",
    "content": "/**\n * @param {number} number\n * @return {boolean}\n */\nexport default function trialDivision(number) {\n  // Check if number is integer.\n  if (number % 1 !== 0) {\n    return false;\n  }\n\n  if (number <= 1) {\n    // If number is less than one then it isn't prime by definition.\n    return false;\n  }\n\n  if (number <= 3) {\n    // All numbers from 2 to 3 are prime.\n    return true;\n  }\n\n  // If the number is not divided by 2 then we may eliminate all further even dividers.\n  if (number % 2 === 0) {\n    return false;\n  }\n\n  // If there is no dividers up to square root of n then there is no higher dividers as well.\n  const dividerLimit = Math.sqrt(number);\n  for (let divider = 3; divider <= dividerLimit; divider += 2) {\n    if (number % divider === 0) {\n      return false;\n    }\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "src/algorithms/math/prime-factors/README.md",
    "content": "# Prime Factors\n\n_Read this in other languages:_\n[简体中文](README.zh-CN.md).\n\n**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.\n\nIf we **can** make it by multiplying other whole numbers it is a **Composite Number**.\n\n![Composite numbers](https://www.mathsisfun.com/numbers/images/prime-composite.svg)\n\n_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_\n\n**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`.\n\n![Factors](https://www.mathsisfun.com/numbers/images/factor-2x3.svg)\n\n_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_\n\n## Finding the prime factors and their count accurately\n\nThe 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.\n\nThe 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.\n\n## Hardy-Ramanujan formula for approximate calculation of prime-factor count\n\nIn 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\nRoughly speaking, this means that most numbers have about this number of distinct prime factors.\n\n## References\n\n- [Prime numbers on Math is Fun](https://www.mathsisfun.com/prime-factorization.html)\n- [Prime numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)\n- [Hardy–Ramanujan theorem on Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem)\n- [Prime factorization of a number on Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82)\n"
  },
  {
    "path": "src/algorithms/math/prime-factors/README.zh-CN.md",
    "content": "# 质数因子\n\n_Read this in other languages:_\n[english](README.md).\n\n**质数** 是一个比 `1` 大的整数，且 **不能**由其它整数相乘得出。前几个质数是: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19`,依此类推。\n\n如果我们**能**通过其它整数相乘得出，我们则称它为**合数**\n\n![Composite numbers](https://www.mathsisfun.com/numbers/images/prime-composite.svg)\n\n_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_\n\n\n**质数因子**是那些相乘得到原始数的[质数](https://en.wikipedia.org/wiki/Prime_number)。例如`39`的质数因子是`3`和`13`，`15`的质数因子是`3`和`5`。\n\n![Factors](https://www.mathsisfun.com/numbers/images/factor-2x3.svg)\n\n_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_\n\n## 正确计算所有的质数因子及其数量\n\n这个方法将自然数`n`从`i = 2`除到`i = n`（仅按质数索引）。且每次循环后`n`的值被`(n / i)`的值替换。\n\n在最坏的情况下，即循环从`i = 2`执行到 `i = n`，上述方法的时间复杂度为`O(n)`。时间复杂度其实可以从`O(n)`减少到`O(sqrt(n))`，通过减少循环的执行次数，从`i = 2`执行到 `i = sqrt(n)`。因为可以确认，当`i`大于`sqrt(n)`时，除了`n`本身，再没有数可以被整除了。\n\n## Hardy-Ramanujan公式用于计算质数因子的个数\n\n1917年，G.H Hardy和Srinivasa Ramanujan提出了一个定理，该定理指出，自然数 `n` 的不同素数的数 `ω(n)` 的正态次序是`log(log(n))`。\n\n粗略地讲，这意味着大多数数字具有这个数量的质数因子。\n\n## References\n\n- [Prime numbers on Math is Fun](https://www.mathsisfun.com/prime-factorization.html)\n- [Prime numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)\n- [Hardy–Ramanujan theorem on Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem)\n- [Prime factorization of a number on Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82)\n"
  },
  {
    "path": "src/algorithms/math/prime-factors/__test__/primeFactors.test.js",
    "content": "import {\n  primeFactors,\n  hardyRamanujan,\n} from '../primeFactors';\n\n/**\n * Calculates the error between exact and approximate prime factor counts.\n * @param {number} exactCount\n * @param {number} approximateCount\n * @returns {number} - approximation error (percentage).\n */\nfunction approximationError(exactCount, approximateCount) {\n  return (Math.abs((exactCount - approximateCount) / exactCount) * 100);\n}\n\ndescribe('primeFactors', () => {\n  it('should find prime factors', () => {\n    expect(primeFactors(1)).toEqual([]);\n    expect(primeFactors(2)).toEqual([2]);\n    expect(primeFactors(3)).toEqual([3]);\n    expect(primeFactors(4)).toEqual([2, 2]);\n    expect(primeFactors(14)).toEqual([2, 7]);\n    expect(primeFactors(40)).toEqual([2, 2, 2, 5]);\n    expect(primeFactors(54)).toEqual([2, 3, 3, 3]);\n    expect(primeFactors(100)).toEqual([2, 2, 5, 5]);\n    expect(primeFactors(156)).toEqual([2, 2, 3, 13]);\n    expect(primeFactors(273)).toEqual([3, 7, 13]);\n    expect(primeFactors(300)).toEqual([2, 2, 3, 5, 5]);\n    expect(primeFactors(980)).toEqual([2, 2, 5, 7, 7]);\n    expect(primeFactors(1000)).toEqual([2, 2, 2, 5, 5, 5]);\n    expect(primeFactors(52734)).toEqual([2, 3, 11, 17, 47]);\n    expect(primeFactors(343434)).toEqual([2, 3, 7, 13, 17, 37]);\n    expect(primeFactors(456745)).toEqual([5, 167, 547]);\n    expect(primeFactors(510510)).toEqual([2, 3, 5, 7, 11, 13, 17]);\n    expect(primeFactors(8735463)).toEqual([3, 3, 11, 88237]);\n    expect(primeFactors(873452453)).toEqual([149, 1637, 3581]);\n  });\n\n  it('should give approximate prime factors count using Hardy-Ramanujan theorem', () => {\n    expect(hardyRamanujan(2)).toBeCloseTo(-0.366, 2);\n    expect(hardyRamanujan(4)).toBeCloseTo(0.326, 2);\n    expect(hardyRamanujan(40)).toBeCloseTo(1.305, 2);\n    expect(hardyRamanujan(156)).toBeCloseTo(1.6193, 2);\n    expect(hardyRamanujan(980)).toBeCloseTo(1.929, 2);\n    expect(hardyRamanujan(52734)).toBeCloseTo(2.386, 2);\n    expect(hardyRamanujan(343434)).toBeCloseTo(2.545, 2);\n    expect(hardyRamanujan(456745)).toBeCloseTo(2.567, 2);\n    expect(hardyRamanujan(510510)).toBeCloseTo(2.575, 2);\n    expect(hardyRamanujan(8735463)).toBeCloseTo(2.771, 2);\n    expect(hardyRamanujan(873452453)).toBeCloseTo(3.024, 2);\n  });\n\n  it('should give correct deviation between exact and approx counts', () => {\n    expect(approximationError(primeFactors(2).length, hardyRamanujan(2)))\n      .toBeCloseTo(136.651, 2);\n\n    expect(approximationError(primeFactors(4).length, hardyRamanujan(2)))\n      .toBeCloseTo(118.325, 2);\n\n    expect(approximationError(primeFactors(40).length, hardyRamanujan(2)))\n      .toBeCloseTo(109.162, 2);\n\n    expect(approximationError(primeFactors(156).length, hardyRamanujan(2)))\n      .toBeCloseTo(109.162, 2);\n\n    expect(approximationError(primeFactors(980).length, hardyRamanujan(2)))\n      .toBeCloseTo(107.330, 2);\n\n    expect(approximationError(primeFactors(52734).length, hardyRamanujan(52734)))\n      .toBeCloseTo(52.274, 2);\n\n    expect(approximationError(primeFactors(343434).length, hardyRamanujan(343434)))\n      .toBeCloseTo(57.578, 2);\n\n    expect(approximationError(primeFactors(456745).length, hardyRamanujan(456745)))\n      .toBeCloseTo(14.420, 2);\n\n    expect(approximationError(primeFactors(510510).length, hardyRamanujan(510510)))\n      .toBeCloseTo(63.201, 2);\n\n    expect(approximationError(primeFactors(8735463).length, hardyRamanujan(8735463)))\n      .toBeCloseTo(30.712, 2);\n\n    expect(approximationError(primeFactors(873452453).length, hardyRamanujan(873452453)))\n      .toBeCloseTo(0.823, 2);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/prime-factors/primeFactors.js",
    "content": "/**\n * Finds prime factors of a number.\n *\n * @param {number} n - the number that is going to be split into prime factors.\n * @returns {number[]} - array of prime factors.\n */\nexport function primeFactors(n) {\n  // Clone n to avoid function arguments override.\n  let nn = n;\n\n  // Array that stores the all the prime factors.\n  const factors = [];\n\n  // Running the loop till sqrt(n) instead of n to optimise time complexity from O(n) to O(sqrt(n)).\n  for (let factor = 2; factor <= Math.sqrt(nn); factor += 1) {\n    // Check that factor divides n without a reminder.\n    while (nn % factor === 0) {\n      // Overriding the value of n.\n      nn /= factor;\n      // Saving the factor.\n      factors.push(factor);\n    }\n  }\n\n  // The ultimate reminder should be a last prime factor,\n  // unless it is not 1 (since 1 is not a prime number).\n  if (nn !== 1) {\n    factors.push(nn);\n  }\n\n  return factors;\n}\n\n/**\n * Hardy-Ramanujan approximation of prime factors count.\n *\n * @param {number} n\n * @returns {number} - approximate number of prime factors.\n */\nexport function hardyRamanujan(n) {\n  return Math.log(Math.log(n));\n}\n"
  },
  {
    "path": "src/algorithms/math/radian/README.md",
    "content": "# Radian\n\nThe **radian** (symbol **rad**) is the unit for measuring angles, and is the \nstandard unit of angular measure used in many areas of mathematics.\n\nThe length of an arc of a unit circle is numerically equal to the measurement \nin radians of the angle that it subtends; one radian is just under `57.3` degrees.\n\nAn arc of a circle with the same length as the radius of that circle subtends an \nangle of `1 radian`. The circumference subtends an angle of `2π radians`.\n\n![Radian](https://upload.wikimedia.org/wikipedia/commons/4/4e/Circle_radians.gif)\n\nA complete revolution is 2π radians (shown here with a circle of radius one and \nthus circumference `2π`).\n\n![2 pi Radian](https://upload.wikimedia.org/wikipedia/commons/6/67/2pi-unrolled.gif)\n\n**Conversions**\n\n| Radians | Degrees |\n| :-----: | :-----: |\n| 0       | 0°      |\n| π/12    | 15°     |\n| π/6     | 30°     |\n| π/4     | 45°     |\n| 1       | 57.3°   |\n| π/3     | 60°     |\n| π/2     | 90°     |\n| π       | 180°    |\n| 2π      | 360°    |\n\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Radian)\n"
  },
  {
    "path": "src/algorithms/math/radian/__test__/degreeToRadian.test.js",
    "content": "import degreeToRadian from '../degreeToRadian';\n\ndescribe('degreeToRadian', () => {\n  it('should convert degree to radian', () => {\n    expect(degreeToRadian(0)).toBe(0);\n    expect(degreeToRadian(45)).toBe(Math.PI / 4);\n    expect(degreeToRadian(90)).toBe(Math.PI / 2);\n    expect(degreeToRadian(180)).toBe(Math.PI);\n    expect(degreeToRadian(270)).toBe((3 * Math.PI) / 2);\n    expect(degreeToRadian(360)).toBe(2 * Math.PI);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/radian/__test__/radianToDegree.test.js",
    "content": "import radianToDegree from '../radianToDegree';\n\ndescribe('radianToDegree', () => {\n  it('should convert radian to degree', () => {\n    expect(radianToDegree(0)).toBe(0);\n    expect(radianToDegree(Math.PI / 4)).toBe(45);\n    expect(radianToDegree(Math.PI / 2)).toBe(90);\n    expect(radianToDegree(Math.PI)).toBe(180);\n    expect(radianToDegree((3 * Math.PI) / 2)).toBe(270);\n    expect(radianToDegree(2 * Math.PI)).toBe(360);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/radian/degreeToRadian.js",
    "content": "/**\n * @param {number} degree\n * @return {number}\n */\nexport default function degreeToRadian(degree) {\n  return degree * (Math.PI / 180);\n}\n"
  },
  {
    "path": "src/algorithms/math/radian/radianToDegree.js",
    "content": "/**\n * @param {number} radian\n * @return {number}\n */\nexport default function radianToDegree(radian) {\n  return radian * (180 / Math.PI);\n}\n"
  },
  {
    "path": "src/algorithms/math/sieve-of-eratosthenes/README.md",
    "content": "# Sieve of Eratosthenes\n\nThe Sieve of Eratosthenes is an algorithm for finding all prime numbers up to some limit `n`.\n\nIt is attributed to Eratosthenes of Cyrene, an ancient Greek mathematician.\n\n## How it works\n\n1. Create a boolean array of `n + 1` positions (to represent the numbers `0` through `n`)\n2. Set positions `0` and `1` to `false`, and the rest to `true`\n3. Start at position `p = 2` (the first prime number)\n4. 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)\n5. 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\n\nWhen the algorithm terminates, the numbers remaining `true` in the array are all \nthe primes below `n`.\n\nAn improvement of this algorithm is, in step 4, start marking multiples \nof `p` from `p * p`, and not from `2 * p`. The reason why this works is because, \nat that point, smaller multiples of `p` will have already been marked `false`.\n\n## Example\n\n![Sieve](https://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif)\n\n## Complexity\n\nThe algorithm has a complexity of `O(n log(log n))`.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)\n"
  },
  {
    "path": "src/algorithms/math/sieve-of-eratosthenes/__test__/sieveOfEratosthenes.test.js",
    "content": "import sieveOfEratosthenes from '../sieveOfEratosthenes';\n\ndescribe('sieveOfEratosthenes', () => {\n  it('should find all primes less than or equal to n', () => {\n    expect(sieveOfEratosthenes(5)).toEqual([2, 3, 5]);\n    expect(sieveOfEratosthenes(10)).toEqual([2, 3, 5, 7]);\n    expect(sieveOfEratosthenes(100)).toEqual([\n      2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,\n      43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/sieve-of-eratosthenes/sieveOfEratosthenes.js",
    "content": "/**\n * @param {number} maxNumber\n * @return {number[]}\n */\nexport default function sieveOfEratosthenes(maxNumber) {\n  const isPrime = new Array(maxNumber + 1).fill(true);\n  isPrime[0] = false;\n  isPrime[1] = false;\n\n  const primes = [];\n\n  for (let number = 2; number <= maxNumber; number += 1) {\n    if (isPrime[number] === true) {\n      primes.push(number);\n\n      /*\n       * Optimisation.\n       * Start marking multiples of `p` from `p * p`, and not from `2 * p`.\n       * The reason why this works is because, at that point, smaller multiples\n       * of `p` will have already been marked `false`.\n       *\n       * Warning: When working with really big numbers, the following line may cause overflow\n       * In that case, it can be changed to:\n       * let nextNumber = 2 * number;\n       */\n      let nextNumber = number * number;\n\n      while (nextNumber <= maxNumber) {\n        isPrime[nextNumber] = false;\n        nextNumber += number;\n      }\n    }\n  }\n\n  return primes;\n}\n"
  },
  {
    "path": "src/algorithms/math/square-root/README.md",
    "content": "# Square Root (Newton's Method)\n\nIn numerical analysis, a branch of mathematics, there are several square root \nalgorithms or methods of computing the principal square root of a non-negative real \nnumber. As, generally, the roots of a function cannot be computed exactly.\nThe root-finding algorithms provide approximations to roots expressed as floating\npoint numbers.\n\nFinding ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) is\nthe same as solving the equation ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) for a\npositive `x`. Therefore, any general numerical root-finding algorithm can be used.\n\n**Newton's method** (also known as the Newton–Raphson method), named after \n_Isaac Newton_ and _Joseph Raphson_, is one example of a root-finding algorithm. It is a \nmethod for finding successively better approximations to the roots of a real-valued function.\n\nLet's start by explaining the general idea of Newton's method and then apply it to our particular\ncase with finding a square root of the number.\n\n## Newton's Method General Idea\n\nThe Newton–Raphson method in one variable is implemented as follows:\n\nThe method starts with a function `f` defined over the real numbers `x`, the function's derivative `f'`, and an \ninitial guess `x0` for a root of the function `f`. If the function satisfies the assumptions made in the derivation \nof the formula and the initial guess is close, then a better approximation `x1` is:\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/52c50eca0b7c4d64ef2fdca678665b73e944cb84)\n\nGeometrically, `(x1, 0)` is the intersection of the `x`-axis and the tangent of \nthe graph of `f` at `(x0, f (x0))`.\n\nThe process is repeated as:\n\n![](https://wikimedia.org/api/rest_v1/media/math/render/svg/710c11b9ec4568d1cfff49b7c7d41e0a7829a736)\n\nuntil a sufficiently accurate value is reached.\n\n![](https://upload.wikimedia.org/wikipedia/commons/e/e0/NewtonIteration_Ani.gif)\n\n## Newton's Method of Finding a Square Root\n\nAs it was mentioned above, finding ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) is\nthe same as solving the equation ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) for a\npositive `x`.\n\nThe derivative of the function `f(x)` in case of square root problem is `2x`.\n\nAfter applying the Newton's formula (see above) we get the following equation for our algorithm iterations:\n\n```text\nx := x - (x² - S) / (2x)\n```\n\nThe `x² − S` above is how far away `x²` is from where it needs to be, and the \ndivision by `2x` is the derivative of `x²`, to scale how much we adjust `x` by how \nquickly `x²` is changing.\n\n## References\n\n- [Methods of computing square roots on Wikipedia](https://en.wikipedia.org/wiki/Methods_of_computing_square_roots)\n- [Newton's method on Wikipedia](https://en.wikipedia.org/wiki/Newton%27s_method)\n"
  },
  {
    "path": "src/algorithms/math/square-root/__test__/squareRoot.test.js",
    "content": "import squareRoot from '../squareRoot';\n\ndescribe('squareRoot', () => {\n  it('should throw for negative numbers', () => {\n    function failingSquareRoot() {\n      squareRoot(-5);\n    }\n    expect(failingSquareRoot).toThrow();\n  });\n\n  it('should correctly calculate square root with default tolerance', () => {\n    expect(squareRoot(0)).toBe(0);\n    expect(squareRoot(1)).toBe(1);\n    expect(squareRoot(2)).toBe(1);\n    expect(squareRoot(3)).toBe(2);\n    expect(squareRoot(4)).toBe(2);\n    expect(squareRoot(15)).toBe(4);\n    expect(squareRoot(16)).toBe(4);\n    expect(squareRoot(256)).toBe(16);\n    expect(squareRoot(473)).toBe(22);\n    expect(squareRoot(14723)).toBe(121);\n  });\n\n  it('should correctly calculate square root for integers with custom tolerance', () => {\n    let tolerance = 1;\n\n    expect(squareRoot(0, tolerance)).toBe(0);\n    expect(squareRoot(1, tolerance)).toBe(1);\n    expect(squareRoot(2, tolerance)).toBe(1.4);\n    expect(squareRoot(3, tolerance)).toBe(1.8);\n    expect(squareRoot(4, tolerance)).toBe(2);\n    expect(squareRoot(15, tolerance)).toBe(3.9);\n    expect(squareRoot(16, tolerance)).toBe(4);\n    expect(squareRoot(256, tolerance)).toBe(16);\n    expect(squareRoot(473, tolerance)).toBe(21.7);\n    expect(squareRoot(14723, tolerance)).toBe(121.3);\n\n    tolerance = 3;\n\n    expect(squareRoot(0, tolerance)).toBe(0);\n    expect(squareRoot(1, tolerance)).toBe(1);\n    expect(squareRoot(2, tolerance)).toBe(1.414);\n    expect(squareRoot(3, tolerance)).toBe(1.732);\n    expect(squareRoot(4, tolerance)).toBe(2);\n    expect(squareRoot(15, tolerance)).toBe(3.873);\n    expect(squareRoot(16, tolerance)).toBe(4);\n    expect(squareRoot(256, tolerance)).toBe(16);\n    expect(squareRoot(473, tolerance)).toBe(21.749);\n    expect(squareRoot(14723, tolerance)).toBe(121.338);\n\n    tolerance = 10;\n\n    expect(squareRoot(0, tolerance)).toBe(0);\n    expect(squareRoot(1, tolerance)).toBe(1);\n    expect(squareRoot(2, tolerance)).toBe(1.4142135624);\n    expect(squareRoot(3, tolerance)).toBe(1.7320508076);\n    expect(squareRoot(4, tolerance)).toBe(2);\n    expect(squareRoot(15, tolerance)).toBe(3.8729833462);\n    expect(squareRoot(16, tolerance)).toBe(4);\n    expect(squareRoot(256, tolerance)).toBe(16);\n    expect(squareRoot(473, tolerance)).toBe(21.7485631709);\n    expect(squareRoot(14723, tolerance)).toBe(121.3383698588);\n  });\n\n  it('should correctly calculate square root for integers with custom tolerance', () => {\n    expect(squareRoot(4.5, 10)).toBe(2.1213203436);\n    expect(squareRoot(217.534, 10)).toBe(14.7490338667);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/math/square-root/squareRoot.js",
    "content": "/**\n * Calculates the square root of the number with given tolerance (precision)\n * by using Newton's method.\n *\n * @param number - the number we want to find a square root for.\n * @param [tolerance] - how many precise numbers after the floating point we want to get.\n * @return {number}\n */\nexport default function squareRoot(number, tolerance = 0) {\n  // For now we won't support operations that involves manipulation with complex numbers.\n  if (number < 0) {\n    throw new Error('The method supports only positive integers');\n  }\n\n  // Handle edge case with finding the square root of zero.\n  if (number === 0) {\n    return 0;\n  }\n\n  // We will start approximation from value 1.\n  let root = 1;\n\n  // Delta is a desired distance between the number and the square of the root.\n  // - if tolerance=0 then delta=1\n  // - if tolerance=1 then delta=0.1\n  // - if tolerance=2 then delta=0.01\n  // - and so on...\n  const requiredDelta = 1 / (10 ** tolerance);\n\n  // Approximating the root value to the point when we get a desired precision.\n  while (Math.abs(number - (root ** 2)) > requiredDelta) {\n    // Newton's method reduces in this case to the so-called Babylonian method.\n    // These methods generally yield approximate results, but can be made arbitrarily\n    // precise by increasing the number of calculation steps.\n    root -= ((root ** 2) - number) / (2 * root);\n  }\n\n  // Cut off undesired floating digits and return the root value.\n  return Math.round(root * (10 ** tolerance)) / (10 ** tolerance);\n}\n"
  },
  {
    "path": "src/algorithms/ml/k-means/README.md",
    "content": "# k-Means Algorithm\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nThe **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.\n\nIn 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.\n\nThe 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.\n\n![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)\n\n_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_\n\nThe algorithm is as follows:\n\n1. Check for errors like invalid/inconsistent data\n2. Initialize the `k` cluster locations with initial/random `k` points\n3. Calculate the distance of each data point from each cluster\n4. Assign the cluster label of each data point equal to that of the cluster at its minimum distance\n5. Calculate the centroid of each cluster based on the data points it contains\n6. Repeat each of the above steps until the centroid locations are varying\n\nHere is a visualization of k-Means clustering for better understanding:\n\n![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif)\n\n_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)_\n\nThe 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.\n\n## Code Examples\n\n- [kMeans.js](./kMeans.js)\n- [kMeans.test.js](./__test__/kMeans.test.js) (test cases)\n\n## References\n\n- [k-Means neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)\n"
  },
  {
    "path": "src/algorithms/ml/k-means/README.pt-BR.md",
    "content": "# Algoritmo k-Means\n\n_Leia isso em outros idiomas:_\n[_English_](README.md)\n\nO **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.\n\nNa 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.\n\nA 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.\n\n![Distância Euclidiana entre dois pontos](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)\n\n_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_\n\nO algoritmo é o seguinte:\n\n1. Verifique se há erros como dados inválidos/inconsistentes\n2. Inicialize os locais do cluster `k` com pontos `k` iniciais/aleatórios\n3. Calcule a distância de cada ponto de dados de cada cluster\n4. Atribua o rótulo do cluster de cada ponto de dados igual ao do cluster em sua distância mínima\n5. Calcule o centroide de cada cluster com base nos pontos de dados que ele contém\n6. Repita cada uma das etapas acima até que as localizações do centroide estejam variando\n\nAqui está uma visualização do agrupamento k-Means para melhor compreensão:\n\n![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif)\n\n_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)_\n\nOs 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.\n\n## Referências\n\n- [k-Means neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)\n"
  },
  {
    "path": "src/algorithms/ml/k-means/__test__/kMeans.test.js",
    "content": "import KMeans from '../kMeans';\n\ndescribe('kMeans', () => {\n  it('should throw an error on invalid data', () => {\n    expect(() => {\n      KMeans();\n    }).toThrow('The data is empty');\n  });\n\n  it('should throw an error on inconsistent data', () => {\n    expect(() => {\n      KMeans([[1, 2], [1]], 2);\n    }).toThrow('Matrices have different shapes');\n  });\n\n  it('should find the nearest neighbour', () => {\n    const data = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]];\n    const k = 2;\n    const expectedClusters = [0, 1, 0, 1, 1, 0, 1];\n    expect(KMeans(data, k)).toEqual(expectedClusters);\n\n    expect(KMeans([[0, 0], [0, 1], [10, 10]], 2)).toEqual(\n      [0, 0, 1],\n    );\n  });\n\n  it('should find the clusters with equal distances', () => {\n    const dataSet = [[0, 0], [1, 1], [2, 2]];\n    const k = 3;\n    const expectedCluster = [0, 1, 2];\n    expect(KMeans(dataSet, k)).toEqual(expectedCluster);\n  });\n\n  it('should find the nearest neighbour in 3D space', () => {\n    const dataSet = [[0, 0, 0], [0, 1, 0], [2, 0, 2]];\n    const k = 2;\n    const expectedCluster = [1, 1, 0];\n    expect(KMeans(dataSet, k)).toEqual(expectedCluster);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/ml/k-means/kMeans.js",
    "content": "import * as mtrx from '../../math/matrix/Matrix';\nimport euclideanDistance from '../../math/euclidean-distance/euclideanDistance';\n\n/**\n * Classifies the point in space based on k-Means algorithm.\n *\n * @param {number[][]} data - array of dataSet points, i.e. [[0, 1], [3, 4], [5, 7]]\n * @param {number} k - number of clusters\n * @return {number[]} - the class of the point\n */\nexport default function KMeans(\n  data,\n  k = 1,\n) {\n  if (!data) {\n    throw new Error('The data is empty');\n  }\n\n  // Assign k clusters locations equal to the location of initial k points.\n  const dataDim = data[0].length;\n  const clusterCenters = data.slice(0, k);\n\n  // Continue optimization till convergence.\n  // Centroids should not be moving once optimized.\n  // Calculate distance of each candidate vector from each cluster center.\n  // Assign cluster number to each data vector according to minimum distance.\n\n  // Matrix of distance from each data point to each cluster centroid.\n  const distances = mtrx.zeros([data.length, k]);\n\n  // Vector data points' classes. The value of -1 means that no class has bee assigned yet.\n  const classes = Array(data.length).fill(-1);\n\n  let iterate = true;\n  while (iterate) {\n    iterate = false;\n\n    // Calculate and store the distance of each data point from each cluster.\n    for (let dataIndex = 0; dataIndex < data.length; dataIndex += 1) {\n      for (let clusterIndex = 0; clusterIndex < k; clusterIndex += 1) {\n        distances[dataIndex][clusterIndex] = euclideanDistance(\n          [clusterCenters[clusterIndex]],\n          [data[dataIndex]],\n        );\n      }\n      // Assign the closest cluster number to each dataSet point.\n      const closestClusterIdx = distances[dataIndex].indexOf(\n        Math.min(...distances[dataIndex]),\n      );\n\n      // Check if data point class has been changed and we still need to re-iterate.\n      if (classes[dataIndex] !== closestClusterIdx) {\n        iterate = true;\n      }\n\n      classes[dataIndex] = closestClusterIdx;\n    }\n\n    // Recalculate cluster centroid values via all dimensions of the points under it.\n    for (let clusterIndex = 0; clusterIndex < k; clusterIndex += 1) {\n      // Reset cluster center coordinates since we need to recalculate them.\n      clusterCenters[clusterIndex] = Array(dataDim).fill(0);\n      let clusterSize = 0;\n      for (let dataIndex = 0; dataIndex < data.length; dataIndex += 1) {\n        if (classes[dataIndex] === clusterIndex) {\n          // Register one more data point of current cluster.\n          clusterSize += 1;\n          for (let dimensionIndex = 0; dimensionIndex < dataDim; dimensionIndex += 1) {\n            // Add data point coordinates to the cluster center coordinates.\n            clusterCenters[clusterIndex][dimensionIndex] += data[dataIndex][dimensionIndex];\n          }\n        }\n      }\n      // Calculate the average for each cluster center coordinate.\n      for (let dimensionIndex = 0; dimensionIndex < dataDim; dimensionIndex += 1) {\n        clusterCenters[clusterIndex][dimensionIndex] = parseFloat(Number(\n          clusterCenters[clusterIndex][dimensionIndex] / clusterSize,\n        ).toFixed(2));\n      }\n    }\n  }\n\n  // Return the clusters assigned.\n  return classes;\n}\n"
  },
  {
    "path": "src/algorithms/ml/knn/README.md",
    "content": "# k-Nearest Neighbors Algorithm\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nThe **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.\n\nIn 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.\n\nThe 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.\n\n![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)\n\n_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_\n\nThe algorithm is as follows:\n\n1. Check for errors like invalid data/labels.\n2. Calculate the euclidean distance of all the data points in training data with the classification point\n3. Sort the distances of points along with their classes in ascending order\n4. Take the initial `K` classes and find the mode to get the most similar class\n5. Report the most similar class\n\nHere is a visualization of k-NN classification for better understanding:\n\n![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg)\n\n_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_\n\nThe 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).\n\nAnother k-NN classification example:\n\n![KNN Visualization 2](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)\n\n_Image source: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_\n\nHere, as we can see, the classification of unknown points will be judged by their proximity to other points.\n\nIt 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`.\n\n## References\n\n- [k-nearest neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)\n"
  },
  {
    "path": "src/algorithms/ml/knn/README.pt-BR.md",
    "content": "# Algoritmo de k-vizinhos mais próximos\n\n_Leia isso em outros idiomas:_\n[_English_](README.md)\n\nO **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.\n\nNa 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.\n\nThe 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.\n\n![Distância Euclidiana entre dois pontos](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)\n\n_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_\n\nO algoritmo é o seguinte:\n\n1. Verifique se há erros como dados/rótulos inválidos.\n2. Calcule a distância euclidiana de todos os pontos de dados nos dados de treinamento com o ponto de classificação\n3. Classifique as distâncias dos pontos junto com suas classes em ordem crescente\n4. Pegue as classes iniciais `K` e encontre o modo para obter a classe mais semelhante\n5. Informe a classe mais semelhante\n\nAqui está uma visualização da classificação k-NN para melhor compreensão:\n\n![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg)\n\n_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_\n\nA 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).\n\nOutro exemplo de classificação k-NN:\n\n![KNN Visualization 2](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)\n\n_Fonte: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_\n\nAqui, como podemos ver, a classificação dos pontos desconhecidos será julgada pela proximidade com outros pontos.\n\nÉ importante notar que `K` é preferível ter valores ímpares para desempate. Normalmente `K` é tomado como `3` ou `5`.\n\n## Referências\n\n- [k-nearest neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)\n"
  },
  {
    "path": "src/algorithms/ml/knn/__test__/knn.test.js",
    "content": "import kNN from '../kNN';\n\ndescribe('kNN', () => {\n  it('should throw an error on invalid data', () => {\n    expect(() => {\n      kNN();\n    }).toThrow('Either dataSet or labels or toClassify were not set');\n  });\n\n  it('should throw an error on invalid labels', () => {\n    const noLabels = () => {\n      kNN([[1, 1]]);\n    };\n    expect(noLabels).toThrow('Either dataSet or labels or toClassify were not set');\n  });\n\n  it('should throw an error on not giving classification vector', () => {\n    const noClassification = () => {\n      kNN([[1, 1]], [1]);\n    };\n    expect(noClassification).toThrow('Either dataSet or labels or toClassify were not set');\n  });\n\n  it('should throw an error on not giving classification vector', () => {\n    const inconsistent = () => {\n      kNN([[1, 1]], [1], [1]);\n    };\n    expect(inconsistent).toThrow('Matrices have different shapes');\n  });\n\n  it('should find the nearest neighbour', () => {\n    let dataSet;\n    let labels;\n    let toClassify;\n    let expectedClass;\n\n    dataSet = [[1, 1], [2, 2]];\n    labels = [1, 2];\n    toClassify = [1, 1];\n    expectedClass = 1;\n    expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);\n\n    dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]];\n    labels = [1, 2, 1, 2, 1, 2, 1];\n    toClassify = [1.25, 1.25];\n    expectedClass = 1;\n    expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);\n\n    dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]];\n    labels = [1, 2, 1, 2, 1, 2, 1];\n    toClassify = [1.25, 1.25];\n    expectedClass = 2;\n    expect(kNN(dataSet, labels, toClassify, 5)).toBe(expectedClass);\n  });\n\n  it('should find the nearest neighbour with equal distances', () => {\n    const dataSet = [[0, 0], [1, 1], [0, 2]];\n    const labels = [1, 3, 3];\n    const toClassify = [0, 1];\n    const expectedClass = 3;\n    expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);\n  });\n\n  it('should find the nearest neighbour in 3D space', () => {\n    const dataSet = [[0, 0, 0], [0, 1, 1], [0, 0, 2]];\n    const labels = [1, 3, 3];\n    const toClassify = [0, 0, 1];\n    const expectedClass = 3;\n    expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/ml/knn/kNN.js",
    "content": "/**\n * Classifies the point in space based on k-nearest neighbors algorithm.\n *\n * @param {number[][]} dataSet - array of data points, i.e. [[0, 1], [3, 4], [5, 7]]\n * @param {number[]} labels - array of classes (labels), i.e. [1, 1, 2]\n * @param {number[]} toClassify - the point in space that needs to be classified, i.e. [5, 4]\n * @param {number} k - number of nearest neighbors which will be taken into account (preferably odd)\n * @return {number} - the class of the point\n */\n\nimport euclideanDistance from '../../math/euclidean-distance/euclideanDistance';\n\nexport default function kNN(\n  dataSet,\n  labels,\n  toClassify,\n  k = 3,\n) {\n  if (!dataSet || !labels || !toClassify) {\n    throw new Error('Either dataSet or labels or toClassify were not set');\n  }\n\n  // Calculate distance from toClassify to each point for all dimensions in dataSet.\n  // Store distance and point's label into distances list.\n  const distances = [];\n  for (let i = 0; i < dataSet.length; i += 1) {\n    distances.push({\n      dist: euclideanDistance([dataSet[i]], [toClassify]),\n      label: labels[i],\n    });\n  }\n\n  // Sort distances list (from closer point to further ones).\n  // Take initial k values, count with class index\n  const kNearest = distances.sort((a, b) => {\n    if (a.dist === b.dist) {\n      return 0;\n    }\n    return a.dist < b.dist ? -1 : 1;\n  }).slice(0, k);\n\n  // Count the number of instances of each class in top k members.\n  const labelsCounter = {};\n  let topClass = 0;\n  let topClassCount = 0;\n  for (let i = 0; i < kNearest.length; i += 1) {\n    if (kNearest[i].label in labelsCounter) {\n      labelsCounter[kNearest[i].label] += 1;\n    } else {\n      labelsCounter[kNearest[i].label] = 1;\n    }\n    if (labelsCounter[kNearest[i].label] > topClassCount) {\n      topClassCount = labelsCounter[kNearest[i].label];\n      topClass = kNearest[i].label;\n    }\n  }\n\n  // Return the class with highest count.\n  return topClass;\n}\n"
  },
  {
    "path": "src/algorithms/search/binary-search/README.es-ES.md",
    "content": "# Búsqueda binaria\n\n_Lea esto en otros idiomas:_\n[English](README.md)\n[Português brasileiro](README.pt-BR.md).\n\nEn informática, la búsqueda binaria, también conocida como búsqueda de medio intervalo\nbúsqueda, búsqueda logarítmica, o corte binario, es un algoritmo de búsqueda\nque encuentra la posición de un valor objetivo dentro de una matriz\nordenada. La búsqueda binaria compara el valor objetivo con el elemento central\nde la matriz; si son desiguales, se elimina la mitad en la que\nla mitad en la que no puede estar el objetivo se elimina y la búsqueda continúa\nen la mitad restante hasta que tenga éxito. Si la búsqueda\ntermina con la mitad restante vacía, el objetivo no está\nen la matriz.\n\n![Búsqueda binaria](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg)\n\n## Complejidad\n\n**Complejidad de tiempo**: `O(log(n))` - ya que dividimos el área de búsqueda en dos para cada\nsiguiente iteración.\n\n## Referencias\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm)\n- [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/search/binary-search/README.md",
    "content": "# Binary Search\n\n_Read this in other languages:_\n[Português brasileiro](README.pt-BR.md).\n[Español](README.es-ES.md).\n\nIn computer science, binary search, also known as half-interval\nsearch, logarithmic search, or binary chop, is a search algorithm\nthat finds the position of a target value within a sorted\narray. Binary search compares the target value to the middle\nelement of the array; if they are unequal, the half in which\nthe target cannot lie is eliminated and the search continues\non the remaining half until it is successful. If the search\nends with the remaining half being empty, the target is not\nin the array.\n\n![Binary Search](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg)\n\n## Complexity\n\n**Time Complexity**: `O(log(n))` - since we split search area by two for every\nnext iteration.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm)\n- [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/search/binary-search/README.pt-BR.md",
    "content": "# Busca Binária\n\n_Leia isso em outras línguas:_\n[english](README.md).\n[Español](README.es-ES.md).\n\nEm 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\nque encontra a posição de um elemento alvo dentro de um\nvetor ordenado. O algoritmo compara o elemento alvo com o elemento central do vetor; se eles são diferentes, a metade em que\no elemento alvo não pode estar é eliminada e a busca continua\nna metade remanescente até que o elemento alvo seja encontrado. Se a busca\nterminar com a metade remanescente vazia, o elemento alvo não está presente no vetor.\n\n![Busca Binária](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg)\n\n## Complexidade\n\n**Complexidade de Tempo**: `O(log(n))` - pois a área de busca é dividida por dois a cada iteração.\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm)\n- [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/search/binary-search/__test__/binarySearch.test.js",
    "content": "import binarySearch from '../binarySearch';\n\ndescribe('binarySearch', () => {\n  it('should search number in sorted array', () => {\n    expect(binarySearch([], 1)).toBe(-1);\n    expect(binarySearch([1], 1)).toBe(0);\n    expect(binarySearch([1, 2], 1)).toBe(0);\n    expect(binarySearch([1, 2], 2)).toBe(1);\n    expect(binarySearch([1, 5, 10, 12], 1)).toBe(0);\n    expect(binarySearch([1, 5, 10, 12, 14, 17, 22, 100], 17)).toBe(5);\n    expect(binarySearch([1, 5, 10, 12, 14, 17, 22, 100], 1)).toBe(0);\n    expect(binarySearch([1, 5, 10, 12, 14, 17, 22, 100], 100)).toBe(7);\n    expect(binarySearch([1, 5, 10, 12, 14, 17, 22, 100], 0)).toBe(-1);\n  });\n\n  it('should search object in sorted array', () => {\n    const sortedArrayOfObjects = [\n      { key: 1, value: 'value1' },\n      { key: 2, value: 'value2' },\n      { key: 3, value: 'value3' },\n    ];\n\n    const comparator = (a, b) => {\n      if (a.key === b.key) return 0;\n      return a.key < b.key ? -1 : 1;\n    };\n\n    expect(binarySearch([], { key: 1 }, comparator)).toBe(-1);\n    expect(binarySearch(sortedArrayOfObjects, { key: 4 }, comparator)).toBe(-1);\n    expect(binarySearch(sortedArrayOfObjects, { key: 1 }, comparator)).toBe(0);\n    expect(binarySearch(sortedArrayOfObjects, { key: 2 }, comparator)).toBe(1);\n    expect(binarySearch(sortedArrayOfObjects, { key: 3 }, comparator)).toBe(2);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/search/binary-search/binarySearch.js",
    "content": "import Comparator from '../../../utils/comparator/Comparator';\n\n/**\n * Binary search implementation.\n *\n * @param {*[]} sortedArray\n * @param {*} seekElement\n * @param {function(a, b)} [comparatorCallback]\n * @return {number}\n */\n\nexport default function binarySearch(sortedArray, seekElement, comparatorCallback) {\n  // Let's create comparator from the comparatorCallback function.\n  // Comparator object will give us common comparison methods like equal() and lessThan().\n  const comparator = new Comparator(comparatorCallback);\n\n  // These two indices will contain current array (sub-array) boundaries.\n  let startIndex = 0;\n  let endIndex = sortedArray.length - 1;\n\n  // Let's continue to split array until boundaries are collapsed\n  // and there is nothing to split anymore.\n  while (startIndex <= endIndex) {\n    // Let's calculate the index of the middle element.\n    const middleIndex = startIndex + Math.floor((endIndex - startIndex) / 2);\n\n    // If we've found the element just return its position.\n    if (comparator.equal(sortedArray[middleIndex], seekElement)) {\n      return middleIndex;\n    }\n\n    // Decide which half to choose for seeking next: left or right one.\n    if (comparator.lessThan(sortedArray[middleIndex], seekElement)) {\n      // Go to the right half of the array.\n      startIndex = middleIndex + 1;\n    } else {\n      // Go to the left half of the array.\n      endIndex = middleIndex - 1;\n    }\n  }\n\n  // Return -1 if we have not found anything.\n  return -1;\n}\n"
  },
  {
    "path": "src/algorithms/search/interpolation-search/README.md",
    "content": "# Interpolation Search\n\n**Interpolation search** is an algorithm for searching for a key in an array that \nhas been ordered by numerical values assigned to the keys (key values).\n\nFor example we have a sorted array of `n` uniformly distributed values `arr[]`, \nand we need to write a function to search for a particular element `x` in the array.\n\n**Linear Search** finds the element in `O(n)` time, **Jump Search** takes `O(√ n)` time \nand **Binary Search** take `O(Log n)` time.\n\nThe **Interpolation Search** is an improvement over Binary Search for instances, \nwhere the values in a sorted array are _uniformly_ distributed. Binary Search \nalways goes to the middle element to check. On the other hand, interpolation \nsearch may go to different locations according to the value of the key being \nsearched. For example, if the value of the key is closer to the last element, \ninterpolation search is likely to start search toward the end side.\n\nTo find the position to be searched, it uses following formula:\n\n```\n// The idea of formula is to return higher value of pos\n// when element to be searched is closer to arr[hi]. And\n// smaller value when closer to arr[lo]\npos = lo + ((x - arr[lo]) * (hi - lo) / (arr[hi] - arr[Lo]))\n\narr[] - Array where elements need to be searched\nx - Element to be searched\nlo - Starting index in arr[]\nhi - Ending index in arr[]\n```\n\n## Complexity\n\n**Time complexity**: `O(log(log(n))`\n\n## References\n\n- [GeeksForGeeks](https://www.geeksforgeeks.org/interpolation-search/)\n- [Wikipedia](https://en.wikipedia.org/wiki/Interpolation_search)\n"
  },
  {
    "path": "src/algorithms/search/interpolation-search/__test__/interpolationSearch.test.js",
    "content": "import interpolationSearch from '../interpolationSearch';\n\ndescribe('interpolationSearch', () => {\n  it('should search elements in sorted array of numbers', () => {\n    expect(interpolationSearch([], 1)).toBe(-1);\n    expect(interpolationSearch([1], 1)).toBe(0);\n    expect(interpolationSearch([1], 0)).toBe(-1);\n    expect(interpolationSearch([1, 1], 1)).toBe(0);\n    expect(interpolationSearch([1, 2], 1)).toBe(0);\n    expect(interpolationSearch([1, 2], 2)).toBe(1);\n    expect(interpolationSearch([10, 20, 30, 40, 50], 40)).toBe(3);\n    expect(interpolationSearch([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 14)).toBe(13);\n    expect(interpolationSearch([1, 6, 7, 8, 12, 13, 14, 19, 21, 23, 24, 24, 24, 300], 24)).toBe(10);\n    expect(interpolationSearch([1, 2, 3, 700, 800, 1200, 1300, 1400, 1900], 600)).toBe(-1);\n    expect(interpolationSearch([1, 2, 3, 700, 800, 1200, 1300, 1400, 1900], 1)).toBe(0);\n    expect(interpolationSearch([1, 2, 3, 700, 800, 1200, 1300, 1400, 1900], 2)).toBe(1);\n    expect(interpolationSearch([1, 2, 3, 700, 800, 1200, 1300, 1400, 1900], 3)).toBe(2);\n    expect(interpolationSearch([1, 2, 3, 700, 800, 1200, 1300, 1400, 1900], 700)).toBe(3);\n    expect(interpolationSearch([1, 2, 3, 700, 800, 1200, 1300, 1400, 1900], 800)).toBe(4);\n    expect(interpolationSearch([0, 2, 3, 700, 800, 1200, 1300, 1400, 1900], 1200)).toBe(5);\n    expect(interpolationSearch([1, 2, 3, 700, 800, 1200, 1300, 1400, 19000], 800)).toBe(4);\n    expect(interpolationSearch([0, 10, 11, 12, 13, 14, 15], 10)).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/search/interpolation-search/interpolationSearch.js",
    "content": "/**\n * Interpolation search implementation.\n *\n * @param {*[]} sortedArray - sorted array with uniformly distributed values\n * @param {*} seekElement\n * @return {number}\n */\nexport default function interpolationSearch(sortedArray, seekElement) {\n  let leftIndex = 0;\n  let rightIndex = sortedArray.length - 1;\n\n  while (leftIndex <= rightIndex) {\n    const rangeDelta = sortedArray[rightIndex] - sortedArray[leftIndex];\n    const indexDelta = rightIndex - leftIndex;\n    const valueDelta = seekElement - sortedArray[leftIndex];\n\n    // If valueDelta is less then zero it means that there is no seek element\n    // exists in array since the lowest element from the range is already higher\n    // then seek element.\n    if (valueDelta < 0) {\n      return -1;\n    }\n\n    // If range delta is zero then subarray contains all the same numbers\n    // and thus there is nothing to search for unless this range is all\n    // consists of seek number.\n    if (!rangeDelta) {\n      // By doing this we're also avoiding division by zero while\n      // calculating the middleIndex later.\n      return sortedArray[leftIndex] === seekElement ? leftIndex : -1;\n    }\n\n    // Do interpolation of the middle index.\n    const middleIndex = leftIndex + Math.floor((valueDelta * indexDelta) / rangeDelta);\n\n    // If we've found the element just return its position.\n    if (sortedArray[middleIndex] === seekElement) {\n      return middleIndex;\n    }\n\n    // Decide which half to choose for seeking next: left or right one.\n    if (sortedArray[middleIndex] < seekElement) {\n      // Go to the right half of the array.\n      leftIndex = middleIndex + 1;\n    } else {\n      // Go to the left half of the array.\n      rightIndex = middleIndex - 1;\n    }\n  }\n\n  return -1;\n}\n"
  },
  {
    "path": "src/algorithms/search/jump-search/README.md",
    "content": "# Jump Search\n\nLike Binary Search, **Jump Search** (or **Block Search**) is a searching algorithm \nfor sorted arrays. The basic idea is to check fewer elements (than linear search) \nby jumping ahead by fixed steps or skipping some elements in place of searching all \nelements.\n\nFor example, suppose we have an array `arr[]` of size `n` and block (to be jumped)\nof size `m`. Then we search at the indexes `arr[0]`, `arr[m]`, `arr[2 * m]`, ..., `arr[k * m]` and \nso on. Once we find the interval `arr[k * m] < x < arr[(k+1) * m]`, we perform a \nlinear search operation from the index `k * m` to find the element `x`.\n\n**What is the optimal block size to be skipped?**\nIn the worst case, we have to do `n/m` jumps and if the last checked value is \ngreater than the element to be searched for, we perform `m - 1` comparisons more \nfor linear search. Therefore the total number of comparisons in the worst case \nwill be `((n/m) + m - 1)`. The value of the function `((n/m) + m - 1)` will be \nminimum when `m = √n`. Therefore, the best step size is `m = √n`.\n\n## Complexity\n\n**Time complexity**: `O(√n)` - because we do search by blocks of size `√n`.\n\n## References\n\n- [GeeksForGeeks](https://www.geeksforgeeks.org/jump-search/)\n- [Wikipedia](https://en.wikipedia.org/wiki/Jump_search)\n"
  },
  {
    "path": "src/algorithms/search/jump-search/__test__/jumpSearch.test.js",
    "content": "import jumpSearch from '../jumpSearch';\n\ndescribe('jumpSearch', () => {\n  it('should search for an element in sorted array', () => {\n    expect(jumpSearch([], 1)).toBe(-1);\n    expect(jumpSearch([1], 2)).toBe(-1);\n    expect(jumpSearch([1], 1)).toBe(0);\n    expect(jumpSearch([1, 2], 1)).toBe(0);\n    expect(jumpSearch([1, 2], 1)).toBe(0);\n    expect(jumpSearch([1, 1, 1], 1)).toBe(0);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 2)).toBe(1);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 0)).toBe(-1);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 0)).toBe(-1);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 7)).toBe(-1);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 5)).toBe(2);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 20)).toBe(4);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 30)).toBe(7);\n    expect(jumpSearch([1, 2, 5, 10, 20, 21, 24, 30, 48], 48)).toBe(8);\n  });\n\n  it('should search object in sorted array', () => {\n    const sortedArrayOfObjects = [\n      { key: 1, value: 'value1' },\n      { key: 2, value: 'value2' },\n      { key: 3, value: 'value3' },\n    ];\n\n    const comparator = (a, b) => {\n      if (a.key === b.key) return 0;\n      return a.key < b.key ? -1 : 1;\n    };\n\n    expect(jumpSearch([], { key: 1 }, comparator)).toBe(-1);\n    expect(jumpSearch(sortedArrayOfObjects, { key: 4 }, comparator)).toBe(-1);\n    expect(jumpSearch(sortedArrayOfObjects, { key: 1 }, comparator)).toBe(0);\n    expect(jumpSearch(sortedArrayOfObjects, { key: 2 }, comparator)).toBe(1);\n    expect(jumpSearch(sortedArrayOfObjects, { key: 3 }, comparator)).toBe(2);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/search/jump-search/jumpSearch.js",
    "content": "import Comparator from '../../../utils/comparator/Comparator';\n\n/**\n * Jump (block) search implementation.\n *\n * @param {*[]} sortedArray\n * @param {*} seekElement\n * @param {function(a, b)} [comparatorCallback]\n * @return {number}\n */\nexport default function jumpSearch(sortedArray, seekElement, comparatorCallback) {\n  const comparator = new Comparator(comparatorCallback);\n  const arraySize = sortedArray.length;\n\n  if (!arraySize) {\n    // We can't find anything in empty array.\n    return -1;\n  }\n\n  // Calculate optimal jump size.\n  // Total number of comparisons in the worst case will be ((arraySize/jumpSize) + jumpSize - 1).\n  // The value of the function ((arraySize/jumpSize) + jumpSize - 1) will be minimum\n  // when jumpSize = √array.length.\n  const jumpSize = Math.floor(Math.sqrt(arraySize));\n\n  // Find the block where the seekElement belong to.\n  let blockStart = 0;\n  let blockEnd = jumpSize;\n  while (comparator.greaterThan(seekElement, sortedArray[Math.min(blockEnd, arraySize) - 1])) {\n    // Jump to the next block.\n    blockStart = blockEnd;\n    blockEnd += jumpSize;\n\n    // If our next block is out of array then we couldn't found the element.\n    if (blockStart > arraySize) {\n      return -1;\n    }\n  }\n\n  // Do linear search for seekElement in subarray starting from blockStart.\n  let currentIndex = blockStart;\n  while (currentIndex < Math.min(blockEnd, arraySize)) {\n    if (comparator.equal(sortedArray[currentIndex], seekElement)) {\n      return currentIndex;\n    }\n\n    currentIndex += 1;\n  }\n\n  return -1;\n}\n"
  },
  {
    "path": "src/algorithms/search/linear-search/README.md",
    "content": "# Linear Search\n\n_Read this in other languages:_\n[Português brasileiro](README.pt-BR.md).\n\nIn computer science, linear search or sequential search is a \nmethod for finding a target value within a list. It sequentially \nchecks each element of the list for the target value until a \nmatch is found or until all the elements have been searched.\nLinear search runs in at worst linear time and makes at most `n` \ncomparisons, where `n` is the length of the list. \n\n![Linear Search](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif)\n\n## Complexity\n\n**Time Complexity**: `O(n)` - since in worst case we're checking each element\nexactly once.\n\n## References\n- [Wikipedia](https://en.wikipedia.org/wiki/Linear_search)\n- [TutorialsPoint](https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm)\n- [Youtube](https://www.youtube.com/watch?v=SGU9duLE30w)\n"
  },
  {
    "path": "src/algorithms/search/linear-search/README.pt-BR.md",
    "content": "# Busca Linear\n\n_Leia isso em outras línguas:_\n[english](README.md).\n\nNa Ciência da Computação, busca linear ou busca sequencial é um método para encontrar um elemento alvo em uma lista. \nO algoritmo verifica sequencialmente cada elemento da lista procurando o elemento alvo até ele ser encontrado ou até ter verificado todos os elementos.\nA Busca linear realiza no máximo `n` comparações, onde `n` é o tamanho da lista.\n\n![Busca Linear](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif)\n\n## Complexidade\n\n**Complexidade de Tempo**: `O(n)` - pois no pior caso devemos verificar cada elemento exatamente uma vez.\n\n## Referências\n- [Wikipedia](https://en.wikipedia.org/wiki/Linear_search)\n- [TutorialsPoint](https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm)\n- [Youtube](https://www.youtube.com/watch?v=SGU9duLE30w)\n"
  },
  {
    "path": "src/algorithms/search/linear-search/__test__/linearSearch.test.js",
    "content": "import linearSearch from '../linearSearch';\n\ndescribe('linearSearch', () => {\n  it('should search all numbers in array', () => {\n    const array = [1, 2, 4, 6, 2];\n\n    expect(linearSearch(array, 10)).toEqual([]);\n    expect(linearSearch(array, 1)).toEqual([0]);\n    expect(linearSearch(array, 2)).toEqual([1, 4]);\n  });\n\n  it('should search all strings in array', () => {\n    const array = ['a', 'b', 'a'];\n\n    expect(linearSearch(array, 'c')).toEqual([]);\n    expect(linearSearch(array, 'b')).toEqual([1]);\n    expect(linearSearch(array, 'a')).toEqual([0, 2]);\n  });\n\n  it('should search through objects as well', () => {\n    const comparatorCallback = (a, b) => {\n      if (a.key === b.key) {\n        return 0;\n      }\n\n      return a.key <= b.key ? -1 : 1;\n    };\n\n    const array = [\n      { key: 5 },\n      { key: 6 },\n      { key: 7 },\n      { key: 6 },\n    ];\n\n    expect(linearSearch(array, { key: 10 }, comparatorCallback)).toEqual([]);\n    expect(linearSearch(array, { key: 5 }, comparatorCallback)).toEqual([0]);\n    expect(linearSearch(array, { key: 6 }, comparatorCallback)).toEqual([1, 3]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/search/linear-search/linearSearch.js",
    "content": "import Comparator from '../../../utils/comparator/Comparator';\n\n/**\n * Linear search implementation.\n *\n * @param {*[]} array\n * @param {*} seekElement\n * @param {function(a, b)} [comparatorCallback]\n * @return {number[]}\n */\nexport default function linearSearch(array, seekElement, comparatorCallback) {\n  const comparator = new Comparator(comparatorCallback);\n  const foundIndices = [];\n\n  array.forEach((element, index) => {\n    if (comparator.equal(element, seekElement)) {\n      foundIndices.push(index);\n    }\n  });\n\n  return foundIndices;\n}\n"
  },
  {
    "path": "src/algorithms/sets/cartesian-product/README.md",
    "content": "# Cartesian Product\n\nIn set theory a Cartesian product is a mathematical operation that returns a set \n(or product set or simply product) from multiple sets. That is, for sets A and B,\nthe Cartesian product A × B is the set of all ordered pairs (a, b)\nwhere a ∈ A and b ∈ B. \n\nCartesian product `AxB` of two sets `A={x,y,z}` and `B={1,2,3}`\n\n![Cartesian Product of Two Sets](https://upload.wikimedia.org/wikipedia/commons/4/4e/Cartesian_Product_qtl1.svg)\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Cartesian_product)\n"
  },
  {
    "path": "src/algorithms/sets/cartesian-product/__test__/cartesianProduct.test.js",
    "content": "import cartesianProduct from '../cartesianProduct';\n\ndescribe('cartesianProduct', () => {\n  it('should return null if there is not enough info for calculation', () => {\n    const product1 = cartesianProduct([1], null);\n    const product2 = cartesianProduct([], null);\n\n    expect(product1).toBeNull();\n    expect(product2).toBeNull();\n  });\n\n  it('should calculate the product of two sets', () => {\n    const product1 = cartesianProduct([1], [1]);\n    const product2 = cartesianProduct([1, 2], [3, 5]);\n\n    expect(product1).toEqual([[1, 1]]);\n    expect(product2).toEqual([[1, 3], [1, 5], [2, 3], [2, 5]]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/cartesian-product/cartesianProduct.js",
    "content": "/**\n * Generates Cartesian Product of two sets.\n * @param {*[]} setA\n * @param {*[]} setB\n * @return {*[]}\n */\nexport default function cartesianProduct(setA, setB) {\n  // Check if input sets are not empty.\n  // Otherwise return null since we can't generate Cartesian Product out of them.\n  if (!setA || !setB || !setA.length || !setB.length) {\n    return null;\n  }\n\n  // Init product set.\n  const product = [];\n\n  // Now, let's go through all elements of a first and second set and form all possible pairs.\n  for (let indexA = 0; indexA < setA.length; indexA += 1) {\n    for (let indexB = 0; indexB < setB.length; indexB += 1) {\n      // Add current product pair to the product set.\n      product.push([setA[indexA], setB[indexB]]);\n    }\n  }\n\n  // Return cartesian product set.\n  return product;\n}\n"
  },
  {
    "path": "src/algorithms/sets/combination-sum/README.md",
    "content": "# Combination Sum Problem\n\nGiven a **set** of candidate numbers (`candidates`) **(without duplicates)** and \na target number (`target`), find all unique combinations in `candidates` where \nthe candidate numbers sums to `target`.\n\nThe **same** repeated number may be chosen from `candidates` unlimited number \nof times.\n\n**Note:**\n\n- All numbers (including `target`) will be positive integers.\n- The solution set must not contain duplicate combinations.\n\n## Examples\n\n```\nInput: candidates = [2,3,6,7], target = 7,\n\nA solution set is:\n[\n  [7],\n  [2,2,3]\n]\n```\n\n```\nInput: candidates = [2,3,5], target = 8,\n\nA solution set is:\n[\n  [2,2,2,2],\n  [2,3,3],\n  [3,5]\n]\n```\n\n## Explanations\n\nSince the problem is to get all the possible results, not the best or the \nnumber of result, thus we don’t need to consider DP (dynamic programming),\nbacktracking approach using recursion is needed to handle it.\n\nHere is an example of decision tree for the situation when `candidates = [2, 3]` and `target = 6`:\n\n```\n                0\n              /   \\\n           +2      +3\n          /   \\      \\\n       +2       +3    +3\n      /  \\     /  \\     \\\n    +2    ✘   ✘   ✘     ✓\n   /  \\\n  ✓    ✘    \n```\n\n## References\n\n- [LeetCode](https://leetcode.com/problems/combination-sum/description/)\n"
  },
  {
    "path": "src/algorithms/sets/combination-sum/__test__/combinationSum.test.js",
    "content": "import combinationSum from '../combinationSum';\n\ndescribe('combinationSum', () => {\n  it('should find all combinations with specific sum', () => {\n    expect(combinationSum([1], 4)).toEqual([\n      [1, 1, 1, 1],\n    ]);\n\n    expect(combinationSum([2, 3, 6, 7], 7)).toEqual([\n      [2, 2, 3],\n      [7],\n    ]);\n\n    expect(combinationSum([2, 3, 5], 8)).toEqual([\n      [2, 2, 2, 2],\n      [2, 3, 3],\n      [3, 5],\n    ]);\n\n    expect(combinationSum([2, 5], 3)).toEqual([]);\n\n    expect(combinationSum([], 3)).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/combination-sum/combinationSum.js",
    "content": "/**\n * @param {number[]} candidates - candidate numbers we're picking from.\n * @param {number} remainingSum - remaining sum after adding candidates to currentCombination.\n * @param {number[][]} finalCombinations - resulting list of combinations.\n * @param {number[]} currentCombination - currently explored candidates.\n * @param {number} startFrom - index of the candidate to start further exploration from.\n * @return {number[][]}\n */\nfunction combinationSumRecursive(\n  candidates,\n  remainingSum,\n  finalCombinations = [],\n  currentCombination = [],\n  startFrom = 0,\n) {\n  if (remainingSum < 0) {\n    // By adding another candidate we've gone below zero.\n    // This would mean that the last candidate was not acceptable.\n    return finalCombinations;\n  }\n\n  if (remainingSum === 0) {\n    // If after adding the previous candidate our remaining sum\n    // became zero - we need to save the current combination since it is one\n    // of the answers we're looking for.\n    finalCombinations.push(currentCombination.slice());\n\n    return finalCombinations;\n  }\n\n  // If we haven't reached zero yet let's continue to add all\n  // possible candidates that are left.\n  for (let candidateIndex = startFrom; candidateIndex < candidates.length; candidateIndex += 1) {\n    const currentCandidate = candidates[candidateIndex];\n\n    // Let's try to add another candidate.\n    currentCombination.push(currentCandidate);\n\n    // Explore further option with current candidate being added.\n    combinationSumRecursive(\n      candidates,\n      remainingSum - currentCandidate,\n      finalCombinations,\n      currentCombination,\n      candidateIndex,\n    );\n\n    // BACKTRACKING.\n    // Let's get back, exclude current candidate and try another ones later.\n    currentCombination.pop();\n  }\n\n  return finalCombinations;\n}\n\n/**\n * Backtracking algorithm of finding all possible combination for specific sum.\n *\n * @param {number[]} candidates\n * @param {number} target\n * @return {number[][]}\n */\nexport default function combinationSum(candidates, target) {\n  return combinationSumRecursive(candidates, target);\n}\n"
  },
  {
    "path": "src/algorithms/sets/combinations/README.md",
    "content": "# Combinations\n\nWhen the order doesn't matter, it is a **Combination**.\n\nWhen the order **does** matter it is a **Permutation**.\n\n**\"My fruit salad is a combination of apples, grapes and bananas\"**\nWe don't care what order the fruits are in, they could also be\n\"bananas, grapes and apples\" or \"grapes, apples and bananas\",\nits the same fruit salad.\n\n## Combinations without repetitions\n\nThis is how lotteries work. The numbers are drawn one at a\ntime, and if we have the lucky numbers (no matter what order)\nwe win!\n\nNo Repetition: such as lottery numbers `(2,14,15,27,30,33)`\n\n**Number of combinations**\n\n![Formula](https://www.mathsisfun.com/combinatorics/images/combinations-no-repeat.png)\n\nwhere `n` is the number of things to choose from, and we choose `r` of them,\nno repetition, order doesn't matter.\n\nIt is often called \"n choose r\" (such as \"16 choose 3\"). And is also known as the Binomial Coefficient.\n\n## Combinations with repetitions\n\nRepetition is Allowed: such as coins in your pocket `(5,5,5,10,10)`\n\nOr let us say there are five flavours of ice cream:\n`banana`, `chocolate`, `lemon`, `strawberry` and `vanilla`.\n\nWe can have three scoops. How many variations will there be?\n\nLet's use letters for the flavours: `{b, c, l, s, v}`.\nExample selections include:\n\n- `{c, c, c}` (3 scoops of chocolate)\n- `{b, l, v}` (one each of banana, lemon and vanilla)\n- `{b, v, v}` (one of banana, two of vanilla)\n\n**Number of combinations**\n\n![Formula](https://www.mathsisfun.com/combinatorics/images/combinations-repeat.gif)\n\nWhere `n` is the number of things to choose from, and we\nchoose `r` of them. Repetition allowed,\norder doesn't matter.\n\n## Cheatsheet\n\n![Permutations and Combinations Overview](./images/overview.png)\n\n![Combinations overview](./images/combinations-overview.jpg)\n\n| | |\n| --- | --- |\n|![Combinations with repetition](./images/combinations-with-repetitions.jpg) | ![Combinations without repetition](./images/combinations-without-repetitions.jpg) |\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Math Is Fun](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)\n- [Permutations/combinations cheat sheets](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)\n"
  },
  {
    "path": "src/algorithms/sets/combinations/__test__/combineWithRepetitions.test.js",
    "content": "import combineWithRepetitions from '../combineWithRepetitions';\nimport factorial from '../../../math/factorial/factorial';\n\ndescribe('combineWithRepetitions', () => {\n  it('should combine string with repetitions', () => {\n    expect(combineWithRepetitions(['A'], 1)).toEqual([\n      ['A'],\n    ]);\n\n    expect(combineWithRepetitions(['A', 'B'], 1)).toEqual([\n      ['A'],\n      ['B'],\n    ]);\n\n    expect(combineWithRepetitions(['A', 'B'], 2)).toEqual([\n      ['A', 'A'],\n      ['A', 'B'],\n      ['B', 'B'],\n    ]);\n\n    expect(combineWithRepetitions(['A', 'B'], 3)).toEqual([\n      ['A', 'A', 'A'],\n      ['A', 'A', 'B'],\n      ['A', 'B', 'B'],\n      ['B', 'B', 'B'],\n    ]);\n\n    expect(combineWithRepetitions(['A', 'B', 'C'], 2)).toEqual([\n      ['A', 'A'],\n      ['A', 'B'],\n      ['A', 'C'],\n      ['B', 'B'],\n      ['B', 'C'],\n      ['C', 'C'],\n    ]);\n\n    expect(combineWithRepetitions(['A', 'B', 'C'], 3)).toEqual([\n      ['A', 'A', 'A'],\n      ['A', 'A', 'B'],\n      ['A', 'A', 'C'],\n      ['A', 'B', 'B'],\n      ['A', 'B', 'C'],\n      ['A', 'C', 'C'],\n      ['B', 'B', 'B'],\n      ['B', 'B', 'C'],\n      ['B', 'C', 'C'],\n      ['C', 'C', 'C'],\n    ]);\n\n    const combinationOptions = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];\n    const combinationSlotsNumber = 4;\n    const combinations = combineWithRepetitions(combinationOptions, combinationSlotsNumber);\n    const n = combinationOptions.length;\n    const r = combinationSlotsNumber;\n    const expectedNumberOfCombinations = factorial((r + n) - 1) / (factorial(r) * factorial(n - 1));\n\n    expect(combinations.length).toBe(expectedNumberOfCombinations);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/combinations/__test__/combineWithoutRepetitions.test.js",
    "content": "import combineWithoutRepetitions from '../combineWithoutRepetitions';\nimport factorial from '../../../math/factorial/factorial';\nimport pascalTriangle from '../../../math/pascal-triangle/pascalTriangle';\n\ndescribe('combineWithoutRepetitions', () => {\n  it('should combine string without repetitions', () => {\n    expect(combineWithoutRepetitions(['A', 'B'], 3)).toEqual([]);\n\n    expect(combineWithoutRepetitions(['A', 'B'], 1)).toEqual([\n      ['A'],\n      ['B'],\n    ]);\n\n    expect(combineWithoutRepetitions(['A'], 1)).toEqual([\n      ['A'],\n    ]);\n\n    expect(combineWithoutRepetitions(['A', 'B'], 2)).toEqual([\n      ['A', 'B'],\n    ]);\n\n    expect(combineWithoutRepetitions(['A', 'B', 'C'], 2)).toEqual([\n      ['A', 'B'],\n      ['A', 'C'],\n      ['B', 'C'],\n    ]);\n\n    expect(combineWithoutRepetitions(['A', 'B', 'C'], 3)).toEqual([\n      ['A', 'B', 'C'],\n    ]);\n\n    expect(combineWithoutRepetitions(['A', 'B', 'C', 'D'], 3)).toEqual([\n      ['A', 'B', 'C'],\n      ['A', 'B', 'D'],\n      ['A', 'C', 'D'],\n      ['B', 'C', 'D'],\n    ]);\n\n    expect(combineWithoutRepetitions(['A', 'B', 'C', 'D', 'E'], 3)).toEqual([\n      ['A', 'B', 'C'],\n      ['A', 'B', 'D'],\n      ['A', 'B', 'E'],\n      ['A', 'C', 'D'],\n      ['A', 'C', 'E'],\n      ['A', 'D', 'E'],\n      ['B', 'C', 'D'],\n      ['B', 'C', 'E'],\n      ['B', 'D', 'E'],\n      ['C', 'D', 'E'],\n    ]);\n\n    const combinationOptions = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];\n    const combinationSlotsNumber = 4;\n    const combinations = combineWithoutRepetitions(combinationOptions, combinationSlotsNumber);\n    const n = combinationOptions.length;\n    const r = combinationSlotsNumber;\n    const expectedNumberOfCombinations = factorial(n) / (factorial(r) * factorial(n - r));\n\n    expect(combinations.length).toBe(expectedNumberOfCombinations);\n\n    // This one is just to see one of the way of Pascal's triangle application.\n    expect(combinations.length).toBe(pascalTriangle(n)[r]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/combinations/combineWithRepetitions.js",
    "content": "/**\n * @param {*[]} comboOptions\n * @param {number} comboLength\n * @return {*[]}\n */\nexport default function combineWithRepetitions(comboOptions, comboLength) {\n  // If the length of the combination is 1 then each element of the original array\n  // is a combination itself.\n  if (comboLength === 1) {\n    return comboOptions.map((comboOption) => [comboOption]);\n  }\n\n  // Init combinations array.\n  const combos = [];\n\n  // Remember characters one by one and concatenate them to combinations of smaller lengths.\n  // We don't extract elements here because the repetitions are allowed.\n  comboOptions.forEach((currentOption, optionIndex) => {\n    // Generate combinations of smaller size.\n    const smallerCombos = combineWithRepetitions(\n      comboOptions.slice(optionIndex),\n      comboLength - 1,\n    );\n\n    // Concatenate currentOption with all combinations of smaller size.\n    smallerCombos.forEach((smallerCombo) => {\n      combos.push([currentOption].concat(smallerCombo));\n    });\n  });\n\n  return combos;\n}\n"
  },
  {
    "path": "src/algorithms/sets/combinations/combineWithoutRepetitions.js",
    "content": "/**\n * @param {*[]} comboOptions\n * @param {number} comboLength\n * @return {*[]}\n */\nexport default function combineWithoutRepetitions(comboOptions, comboLength) {\n  // If the length of the combination is 1 then each element of the original array\n  // is a combination itself.\n  if (comboLength === 1) {\n    return comboOptions.map((comboOption) => [comboOption]);\n  }\n\n  // Init combinations array.\n  const combos = [];\n\n  // Extract characters one by one and concatenate them to combinations of smaller lengths.\n  // We need to extract them because we don't want to have repetitions after concatenation.\n  comboOptions.forEach((currentOption, optionIndex) => {\n    // Generate combinations of smaller size.\n    const smallerCombos = combineWithoutRepetitions(\n      comboOptions.slice(optionIndex + 1),\n      comboLength - 1,\n    );\n\n    // Concatenate currentOption with all combinations of smaller size.\n    smallerCombos.forEach((smallerCombo) => {\n      combos.push([currentOption].concat(smallerCombo));\n    });\n  });\n\n  return combos;\n}\n"
  },
  {
    "path": "src/algorithms/sets/fisher-yates/README.md",
    "content": "# Fisher–Yates shuffle\n\nThe Fisher–Yates shuffle is an algorithm for generating a random \npermutation of a finite sequence—in plain terms, the algorithm \nshuffles the sequence. The algorithm effectively puts all the \nelements into a hat; it continually determines the next element \nby randomly drawing an element from the hat until no elements \nremain. The algorithm produces an unbiased permutation: every \npermutation is equally likely. The modern version of the \nalgorithm is efficient: it takes time proportional to the \nnumber of items being shuffled and shuffles them in place.\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)\n"
  },
  {
    "path": "src/algorithms/sets/fisher-yates/__test__/fisherYates.test.js",
    "content": "import fisherYates from '../fisherYates';\nimport { sortedArr } from '../../../sorting/SortTester';\nimport QuickSort from '../../../sorting/quick-sort/QuickSort';\n\ndescribe('fisherYates', () => {\n  it('should shuffle small arrays', () => {\n    expect(fisherYates([])).toEqual([]);\n    expect(fisherYates([1])).toEqual([1]);\n  });\n\n  it('should shuffle array randomly', () => {\n    const shuffledArray = fisherYates(sortedArr);\n    const sorter = new QuickSort();\n\n    expect(shuffledArray.length).toBe(sortedArr.length);\n    expect(shuffledArray).not.toEqual(sortedArr);\n    expect(sorter.sort(shuffledArray)).toEqual(sortedArr);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/fisher-yates/fisherYates.js",
    "content": "/**\n * @param {*[]} originalArray\n * @return {*[]}\n */\nexport default function fisherYates(originalArray) {\n  // Clone array from preventing original array from modification (for testing purpose).\n  const array = originalArray.slice(0);\n\n  for (let i = (array.length - 1); i > 0; i -= 1) {\n    const randomIndex = Math.floor(Math.random() * (i + 1));\n    [array[i], array[randomIndex]] = [array[randomIndex], array[i]];\n  }\n\n  return array;\n}\n"
  },
  {
    "path": "src/algorithms/sets/knapsack-problem/Knapsack.js",
    "content": "import MergeSort from '../../sorting/merge-sort/MergeSort';\n\nexport default class Knapsack {\n  /**\n   * @param {KnapsackItem[]} possibleItems\n   * @param {number} weightLimit\n   */\n  constructor(possibleItems, weightLimit) {\n    this.selectedItems = [];\n    this.weightLimit = weightLimit;\n    this.possibleItems = possibleItems;\n  }\n\n  sortPossibleItemsByWeight() {\n    this.possibleItems = new MergeSort({\n      /**\n       * @var KnapsackItem itemA\n       * @var KnapsackItem itemB\n       */\n      compareCallback: (itemA, itemB) => {\n        if (itemA.weight === itemB.weight) {\n          return 0;\n        }\n\n        return itemA.weight < itemB.weight ? -1 : 1;\n      },\n    }).sort(this.possibleItems);\n  }\n\n  sortPossibleItemsByValue() {\n    this.possibleItems = new MergeSort({\n      /**\n       * @var KnapsackItem itemA\n       * @var KnapsackItem itemB\n       */\n      compareCallback: (itemA, itemB) => {\n        if (itemA.value === itemB.value) {\n          return 0;\n        }\n\n        return itemA.value > itemB.value ? -1 : 1;\n      },\n    }).sort(this.possibleItems);\n  }\n\n  sortPossibleItemsByValuePerWeightRatio() {\n    this.possibleItems = new MergeSort({\n      /**\n       * @var KnapsackItem itemA\n       * @var KnapsackItem itemB\n       */\n      compareCallback: (itemA, itemB) => {\n        if (itemA.valuePerWeightRatio === itemB.valuePerWeightRatio) {\n          return 0;\n        }\n\n        return itemA.valuePerWeightRatio > itemB.valuePerWeightRatio ? -1 : 1;\n      },\n    }).sort(this.possibleItems);\n  }\n\n  // Solve 0/1 knapsack problem\n  // Dynamic Programming approach.\n  solveZeroOneKnapsackProblem() {\n    // We do two sorts because in case of equal weights but different values\n    // we need to take the most valuable items first.\n    this.sortPossibleItemsByValue();\n    this.sortPossibleItemsByWeight();\n\n    this.selectedItems = [];\n\n    // Create knapsack values matrix.\n    const numberOfRows = this.possibleItems.length;\n    const numberOfColumns = this.weightLimit;\n    const knapsackMatrix = Array(numberOfRows).fill(null).map(() => {\n      return Array(numberOfColumns + 1).fill(null);\n    });\n\n    // Fill the first column with zeros since it would mean that there is\n    // no items we can add to knapsack in case if weight limitation is zero.\n    for (let itemIndex = 0; itemIndex < this.possibleItems.length; itemIndex += 1) {\n      knapsackMatrix[itemIndex][0] = 0;\n    }\n\n    // Fill the first row with max possible values we would get by just adding\n    // or not adding the first item to the knapsack.\n    for (let weightIndex = 1; weightIndex <= this.weightLimit; weightIndex += 1) {\n      const itemIndex = 0;\n      const itemWeight = this.possibleItems[itemIndex].weight;\n      const itemValue = this.possibleItems[itemIndex].value;\n      knapsackMatrix[itemIndex][weightIndex] = itemWeight <= weightIndex ? itemValue : 0;\n    }\n\n    // Go through combinations of how we may add items to knapsack and\n    // define what weight/value we would receive using Dynamic Programming\n    // approach.\n    for (let itemIndex = 1; itemIndex < this.possibleItems.length; itemIndex += 1) {\n      for (let weightIndex = 1; weightIndex <= this.weightLimit; weightIndex += 1) {\n        const currentItemWeight = this.possibleItems[itemIndex].weight;\n        const currentItemValue = this.possibleItems[itemIndex].value;\n\n        if (currentItemWeight > weightIndex) {\n          // In case if item's weight is bigger then currently allowed weight\n          // then we can't add it to knapsack and the max possible value we can\n          // gain at the moment is the max value we got for previous item.\n          knapsackMatrix[itemIndex][weightIndex] = knapsackMatrix[itemIndex - 1][weightIndex];\n        } else {\n          // Else we need to consider the max value we can gain at this point by adding\n          // current value or just by keeping the previous item for current weight.\n          knapsackMatrix[itemIndex][weightIndex] = Math.max(\n            currentItemValue + knapsackMatrix[itemIndex - 1][weightIndex - currentItemWeight],\n            knapsackMatrix[itemIndex - 1][weightIndex],\n          );\n        }\n      }\n    }\n\n    // Now let's trace back the knapsack matrix to see what items we're going to add\n    // to the knapsack.\n    let itemIndex = this.possibleItems.length - 1;\n    let weightIndex = this.weightLimit;\n\n    while (itemIndex > 0) {\n      const currentItem = this.possibleItems[itemIndex];\n      const prevItem = this.possibleItems[itemIndex - 1];\n\n      // Check if matrix value came from top (from previous item).\n      // In this case this would mean that we need to include previous item\n      // to the list of selected items.\n      if (\n        knapsackMatrix[itemIndex][weightIndex]\n        && knapsackMatrix[itemIndex][weightIndex] === knapsackMatrix[itemIndex - 1][weightIndex]\n      ) {\n        // Check if there are several items with the same weight but with the different values.\n        // We need to add highest item in the matrix that is possible to get the highest value.\n        const prevSumValue = knapsackMatrix[itemIndex - 1][weightIndex];\n        const prevPrevSumValue = knapsackMatrix[itemIndex - 2][weightIndex];\n        if (\n          !prevSumValue\n          || (prevSumValue && prevPrevSumValue !== prevSumValue)\n        ) {\n          this.selectedItems.push(prevItem);\n        }\n      } else if (knapsackMatrix[itemIndex - 1][weightIndex - currentItem.weight]) {\n        this.selectedItems.push(prevItem);\n        weightIndex -= currentItem.weight;\n      }\n\n      itemIndex -= 1;\n    }\n  }\n\n  // Solve unbounded knapsack problem.\n  // Greedy approach.\n  solveUnboundedKnapsackProblem() {\n    this.sortPossibleItemsByValue();\n    this.sortPossibleItemsByValuePerWeightRatio();\n\n    for (let itemIndex = 0; itemIndex < this.possibleItems.length; itemIndex += 1) {\n      if (this.totalWeight < this.weightLimit) {\n        const currentItem = this.possibleItems[itemIndex];\n\n        // Detect how much of current items we can push to knapsack.\n        const availableWeight = this.weightLimit - this.totalWeight;\n        const maxPossibleItemsCount = Math.floor(availableWeight / currentItem.weight);\n\n        if (maxPossibleItemsCount > currentItem.itemsInStock) {\n          // If we have more items in stock then it is allowed to add\n          // let's add the maximum allowed number of them.\n          currentItem.quantity = currentItem.itemsInStock;\n        } else if (maxPossibleItemsCount) {\n          // In case if we don't have specified number of items in stock\n          // let's add only items we have in stock.\n          currentItem.quantity = maxPossibleItemsCount;\n        }\n\n        this.selectedItems.push(currentItem);\n      }\n    }\n  }\n\n  get totalValue() {\n    /** @var {KnapsackItem} item */\n    return this.selectedItems.reduce((accumulator, item) => {\n      return accumulator + item.totalValue;\n    }, 0);\n  }\n\n  get totalWeight() {\n    /** @var {KnapsackItem} item */\n    return this.selectedItems.reduce((accumulator, item) => {\n      return accumulator + item.totalWeight;\n    }, 0);\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sets/knapsack-problem/KnapsackItem.js",
    "content": "export default class KnapsackItem {\n  /**\n   * @param {Object} itemSettings - knapsack item settings,\n   * @param {number} itemSettings.value - value of the item.\n   * @param {number} itemSettings.weight - weight of the item.\n   * @param {number} itemSettings.itemsInStock - how many items are available to be added.\n   */\n  constructor({ value, weight, itemsInStock = 1 }) {\n    this.value = value;\n    this.weight = weight;\n    this.itemsInStock = itemsInStock;\n    // Actual number of items that is going to be added to knapsack.\n    this.quantity = 1;\n  }\n\n  get totalValue() {\n    return this.value * this.quantity;\n  }\n\n  get totalWeight() {\n    return this.weight * this.quantity;\n  }\n\n  // This coefficient shows how valuable the 1 unit of weight is\n  // for current item.\n  get valuePerWeightRatio() {\n    return this.value / this.weight;\n  }\n\n  toString() {\n    return `v${this.value} w${this.weight} x ${this.quantity}`;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sets/knapsack-problem/README.md",
    "content": "# Knapsack Problem\n\nThe knapsack problem or rucksack problem is a problem in \ncombinatorial optimization: Given a set of items, each with \na weight and a value, determine the number of each item to \ninclude in a collection so that the total weight is less \nthan or equal to a given limit and the total value is as \nlarge as possible.\n\nIt derives its name from the problem faced by someone who is \nconstrained by a fixed-size knapsack and must fill it with the \nmost valuable items.\n\nExample of a one-dimensional (constraint) knapsack problem: \nwhich boxes should be chosen to maximize the amount of money \nwhile still keeping the overall weight under or equal to 15 kg?\n\n![knapsack problem](https://upload.wikimedia.org/wikipedia/commons/f/fd/Knapsack.svg)\n\n## Definition\n\n### 0/1 knapsack problem\n\nThe most common problem being solved is the **0/1 knapsack problem**, \nwhich restricts the number `xi` of copies of each kind of item to zero or one.\n\nGiven a set of n items numbered from `1` up to `n`, each with a \nweight `wi` and a value `vi`, along with a maximum weight \ncapacity `W`,\n\nmaximize ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)\n\nsubject to ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)\nand ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/07dda71da2a630762c7b21b51ea54f86f422f951)\n\nHere `xi` represents the number of instances of item `i` to \ninclude in the knapsack. Informally, the problem is to maximize \nthe sum of the values of the items in the knapsack so that the \nsum of the weights is less than or equal to the knapsack's \ncapacity.\n\n### Bounded knapsack problem (BKP)\n\nThe **bounded knapsack problem (BKP)** removes the restriction \nthat there is only one of each item, but restricts the number \n`xi` of copies of each kind of item to a maximum non-negative \ninteger value `c`:\n\nmaximize ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)\n\nsubject to ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)\nand ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/6c8c5ac4f8247b3b8e01e89de76a1df0ea969821)\n\n### Unbounded knapsack problem (UKP)\n\nThe **unbounded knapsack problem (UKP)** places no upper bound \non the number of copies of each kind of item and can be \nformulated as above except for that the only restriction \non `xi` is that it is a non-negative integer.\n\nmaximize ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)\n\nsubject to ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176) \nand ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/90a99710f61d5dea19e49ae5b31164d2b56b07e3)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Knapsack_problem)\n- [0/1 Knapsack Problem on YouTube](https://www.youtube.com/watch?v=8LusJS5-AGo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js",
    "content": "import Knapsack from '../Knapsack';\nimport KnapsackItem from '../KnapsackItem';\n\ndescribe('Knapsack', () => {\n  it('should solve 0/1 knapsack problem', () => {\n    const possibleKnapsackItems = [\n      new KnapsackItem({ value: 1, weight: 1 }),\n      new KnapsackItem({ value: 4, weight: 3 }),\n      new KnapsackItem({ value: 5, weight: 4 }),\n      new KnapsackItem({ value: 7, weight: 5 }),\n    ];\n\n    const maxKnapsackWeight = 7;\n\n    const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight);\n\n    knapsack.solveZeroOneKnapsackProblem();\n\n    expect(knapsack.totalValue).toBe(9);\n    expect(knapsack.totalWeight).toBe(7);\n    expect(knapsack.selectedItems.length).toBe(2);\n    expect(knapsack.selectedItems[0].toString()).toBe('v5 w4 x 1');\n    expect(knapsack.selectedItems[1].toString()).toBe('v4 w3 x 1');\n  });\n\n  it('should solve 0/1 knapsack problem regardless of items order', () => {\n    const possibleKnapsackItems = [\n      new KnapsackItem({ value: 5, weight: 4 }),\n      new KnapsackItem({ value: 1, weight: 1 }),\n      new KnapsackItem({ value: 7, weight: 5 }),\n      new KnapsackItem({ value: 4, weight: 3 }),\n    ];\n\n    const maxKnapsackWeight = 7;\n\n    const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight);\n\n    knapsack.solveZeroOneKnapsackProblem();\n\n    expect(knapsack.totalValue).toBe(9);\n    expect(knapsack.totalWeight).toBe(7);\n    expect(knapsack.selectedItems.length).toBe(2);\n    expect(knapsack.selectedItems[0].toString()).toBe('v5 w4 x 1');\n    expect(knapsack.selectedItems[1].toString()).toBe('v4 w3 x 1');\n  });\n\n  it('should solve 0/1 knapsack problem with impossible items set', () => {\n    const possibleKnapsackItems = [\n      new KnapsackItem({ value: 5, weight: 40 }),\n      new KnapsackItem({ value: 1, weight: 10 }),\n      new KnapsackItem({ value: 7, weight: 50 }),\n      new KnapsackItem({ value: 4, weight: 30 }),\n    ];\n\n    const maxKnapsackWeight = 7;\n\n    const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight);\n\n    knapsack.solveZeroOneKnapsackProblem();\n\n    expect(knapsack.totalValue).toBe(0);\n    expect(knapsack.totalWeight).toBe(0);\n    expect(knapsack.selectedItems.length).toBe(0);\n  });\n\n  it('should solve 0/1 knapsack problem with all equal weights', () => {\n    const possibleKnapsackItems = [\n      new KnapsackItem({ value: 5, weight: 1 }),\n      new KnapsackItem({ value: 1, weight: 1 }),\n      new KnapsackItem({ value: 7, weight: 1 }),\n      new KnapsackItem({ value: 4, weight: 1 }),\n      new KnapsackItem({ value: 4, weight: 1 }),\n      new KnapsackItem({ value: 4, weight: 1 }),\n    ];\n\n    const maxKnapsackWeight = 3;\n\n    const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight);\n\n    knapsack.solveZeroOneKnapsackProblem();\n\n    expect(knapsack.totalValue).toBe(16);\n    expect(knapsack.totalWeight).toBe(3);\n    expect(knapsack.selectedItems.length).toBe(3);\n    expect(knapsack.selectedItems[0].toString()).toBe('v4 w1 x 1');\n    expect(knapsack.selectedItems[1].toString()).toBe('v5 w1 x 1');\n    expect(knapsack.selectedItems[2].toString()).toBe('v7 w1 x 1');\n  });\n\n  it('should solve unbound knapsack problem', () => {\n    const possibleKnapsackItems = [\n      new KnapsackItem({ value: 84, weight: 7 }), // v/w ratio is 12\n      new KnapsackItem({ value: 5, weight: 2 }), // v/w ratio is 2.5\n      new KnapsackItem({ value: 12, weight: 3 }), // v/w ratio is 4\n      new KnapsackItem({ value: 10, weight: 1 }), // v/w ratio is 10\n      new KnapsackItem({ value: 20, weight: 2 }), // v/w ratio is 10\n    ];\n\n    const maxKnapsackWeight = 15;\n\n    const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight);\n\n    knapsack.solveUnboundedKnapsackProblem();\n\n    expect(knapsack.totalValue).toBe(84 + 20 + 12 + 10 + 5);\n    expect(knapsack.totalWeight).toBe(15);\n    expect(knapsack.selectedItems.length).toBe(5);\n    expect(knapsack.selectedItems[0].toString()).toBe('v84 w7 x 1');\n    expect(knapsack.selectedItems[1].toString()).toBe('v20 w2 x 1');\n    expect(knapsack.selectedItems[2].toString()).toBe('v10 w1 x 1');\n    expect(knapsack.selectedItems[3].toString()).toBe('v12 w3 x 1');\n    expect(knapsack.selectedItems[4].toString()).toBe('v5 w2 x 1');\n  });\n\n  it('should solve unbound knapsack problem with items in stock', () => {\n    const possibleKnapsackItems = [\n      new KnapsackItem({ value: 84, weight: 7, itemsInStock: 3 }), // v/w ratio is 12\n      new KnapsackItem({ value: 5, weight: 2, itemsInStock: 2 }), // v/w ratio is 2.5\n      new KnapsackItem({ value: 12, weight: 3, itemsInStock: 1 }), // v/w ratio is 4\n      new KnapsackItem({ value: 10, weight: 1, itemsInStock: 6 }), // v/w ratio is 10\n      new KnapsackItem({ value: 20, weight: 2, itemsInStock: 8 }), // v/w ratio is 10\n    ];\n\n    const maxKnapsackWeight = 17;\n\n    const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight);\n\n    knapsack.solveUnboundedKnapsackProblem();\n\n    expect(knapsack.totalValue).toBe(84 + 84 + 20 + 10);\n    expect(knapsack.totalWeight).toBe(17);\n    expect(knapsack.selectedItems.length).toBe(3);\n    expect(knapsack.selectedItems[0].toString()).toBe('v84 w7 x 2');\n    expect(knapsack.selectedItems[1].toString()).toBe('v20 w2 x 1');\n    expect(knapsack.selectedItems[2].toString()).toBe('v10 w1 x 1');\n  });\n\n  it('should solve unbound knapsack problem with items in stock and max weight more than sum of all items', () => {\n    const possibleKnapsackItems = [\n      new KnapsackItem({ value: 84, weight: 7, itemsInStock: 3 }), // v/w ratio is 12\n      new KnapsackItem({ value: 5, weight: 2, itemsInStock: 2 }), // v/w ratio is 2.5\n      new KnapsackItem({ value: 12, weight: 3, itemsInStock: 1 }), // v/w ratio is 4\n      new KnapsackItem({ value: 10, weight: 1, itemsInStock: 6 }), // v/w ratio is 10\n      new KnapsackItem({ value: 20, weight: 2, itemsInStock: 8 }), // v/w ratio is 10\n    ];\n\n    const maxKnapsackWeight = 60;\n\n    const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight);\n\n    knapsack.solveUnboundedKnapsackProblem();\n\n    expect(knapsack.totalValue).toBe((3 * 84) + (2 * 5) + (1 * 12) + (6 * 10) + (8 * 20));\n    expect(knapsack.totalWeight).toBe((3 * 7) + (2 * 2) + (1 * 3) + (6 * 1) + (8 * 2));\n    expect(knapsack.selectedItems.length).toBe(5);\n    expect(knapsack.selectedItems[0].toString()).toBe('v84 w7 x 3');\n    expect(knapsack.selectedItems[1].toString()).toBe('v20 w2 x 8');\n    expect(knapsack.selectedItems[2].toString()).toBe('v10 w1 x 6');\n    expect(knapsack.selectedItems[3].toString()).toBe('v12 w3 x 1');\n    expect(knapsack.selectedItems[4].toString()).toBe('v5 w2 x 2');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/knapsack-problem/__test__/KnapsackItem.test.js",
    "content": "import KnapsackItem from '../KnapsackItem';\n\ndescribe('KnapsackItem', () => {\n  it('should create knapsack item and count its total weight and value', () => {\n    const knapsackItem = new KnapsackItem({ value: 3, weight: 2 });\n\n    expect(knapsackItem.value).toBe(3);\n    expect(knapsackItem.weight).toBe(2);\n    expect(knapsackItem.quantity).toBe(1);\n    expect(knapsackItem.valuePerWeightRatio).toBe(1.5);\n    expect(knapsackItem.toString()).toBe('v3 w2 x 1');\n    expect(knapsackItem.totalValue).toBe(3);\n    expect(knapsackItem.totalWeight).toBe(2);\n\n    knapsackItem.quantity = 0;\n\n    expect(knapsackItem.value).toBe(3);\n    expect(knapsackItem.weight).toBe(2);\n    expect(knapsackItem.quantity).toBe(0);\n    expect(knapsackItem.valuePerWeightRatio).toBe(1.5);\n    expect(knapsackItem.toString()).toBe('v3 w2 x 0');\n    expect(knapsackItem.totalValue).toBe(0);\n    expect(knapsackItem.totalWeight).toBe(0);\n\n    knapsackItem.quantity = 2;\n\n    expect(knapsackItem.value).toBe(3);\n    expect(knapsackItem.weight).toBe(2);\n    expect(knapsackItem.quantity).toBe(2);\n    expect(knapsackItem.valuePerWeightRatio).toBe(1.5);\n    expect(knapsackItem.toString()).toBe('v3 w2 x 2');\n    expect(knapsackItem.totalValue).toBe(6);\n    expect(knapsackItem.totalWeight).toBe(4);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/longest-common-subsequence/README.md",
    "content": "# Longest common subsequence problem\n\nThe longest common subsequence (LCS) problem is the problem of finding \nthe longest subsequence common to all sequences in a set of sequences \n(often just two sequences). It differs from the longest common substring\nproblem: unlike substrings, subsequences are not required to occupy \nconsecutive positions within the original sequences. \n\n## Application\n\nThe longest common subsequence problem is a classic computer science \nproblem, the basis of data comparison programs such as the diff utility, \nand has applications in bioinformatics. It is also widely used by \nrevision control systems such as Git for reconciling multiple changes \nmade to a revision-controlled collection of files.\n\n## Example\n\n- LCS for input Sequences `ABCDGH` and `AEDFHR` is `ADH` of length 3.\n- LCS for input Sequences `AGGTAB` and `GXTXAYB` is `GTAB` of length 4.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem)\n- [YouTube](https://www.youtube.com/watch?v=NnD96abizww&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sets/longest-common-subsequence/__test__/longestCommonSubsequence.test.js",
    "content": "import longestCommonSubsequence from '../longestCommonSubsequence';\n\ndescribe('longestCommonSubsequence', () => {\n  it('should find longest common subsequence for two strings', () => {\n    expect(longestCommonSubsequence([''], [''])).toEqual(['']);\n\n    expect(longestCommonSubsequence([''], ['A', 'B', 'C'])).toEqual(['']);\n\n    expect(longestCommonSubsequence(['A', 'B', 'C'], [''])).toEqual(['']);\n\n    expect(longestCommonSubsequence(\n      ['A', 'B', 'C'],\n      ['D', 'E', 'F', 'G'],\n    )).toEqual(['']);\n\n    expect(longestCommonSubsequence(\n      ['A', 'B', 'C', 'D', 'G', 'H'],\n      ['A', 'E', 'D', 'F', 'H', 'R'],\n    )).toEqual(['A', 'D', 'H']);\n\n    expect(longestCommonSubsequence(\n      ['A', 'G', 'G', 'T', 'A', 'B'],\n      ['G', 'X', 'T', 'X', 'A', 'Y', 'B'],\n    )).toEqual(['G', 'T', 'A', 'B']);\n\n    expect(longestCommonSubsequence(\n      ['A', 'B', 'C', 'D', 'A', 'F'],\n      ['A', 'C', 'B', 'C', 'F'],\n    )).toEqual(['A', 'B', 'C', 'F']);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/longest-common-subsequence/__test__/longestCommonSubsequenceRecursive.test.js",
    "content": "import longestCommonSubsequence from '../longestCommonSubsequenceRecursive';\n\ndescribe('longestCommonSubsequenceRecursive', () => {\n  it('should find longest common substring between two strings', () => {\n    expect(longestCommonSubsequence('', '')).toBe('');\n    expect(longestCommonSubsequence('ABC', '')).toBe('');\n    expect(longestCommonSubsequence('', 'ABC')).toBe('');\n    expect(longestCommonSubsequence('ABABC', 'BABCA')).toBe('BABC');\n    expect(longestCommonSubsequence('BABCA', 'ABCBA')).toBe('ABCA');\n    expect(longestCommonSubsequence('sea', 'eat')).toBe('ea');\n    expect(longestCommonSubsequence('algorithms', 'rithm')).toBe('rithm');\n    expect(longestCommonSubsequence(\n      'Algorithms and data structures implemented in JavaScript',\n      'Here you may find Algorithms and data structures that are implemented in JavaScript',\n    )).toBe('Algorithms and data structures implemented in JavaScript');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/longest-common-subsequence/longestCommonSubsequence.js",
    "content": "/**\n * @param {string[]} set1\n * @param {string[]} set2\n * @return {string[]}\n */\nexport default function longestCommonSubsequence(set1, set2) {\n  // Init LCS matrix.\n  const lcsMatrix = Array(set2.length + 1).fill(null).map(() => Array(set1.length + 1).fill(null));\n\n  // Fill first row with zeros.\n  for (let columnIndex = 0; columnIndex <= set1.length; columnIndex += 1) {\n    lcsMatrix[0][columnIndex] = 0;\n  }\n\n  // Fill first column with zeros.\n  for (let rowIndex = 0; rowIndex <= set2.length; rowIndex += 1) {\n    lcsMatrix[rowIndex][0] = 0;\n  }\n\n  // Fill rest of the column that correspond to each of two strings.\n  for (let rowIndex = 1; rowIndex <= set2.length; rowIndex += 1) {\n    for (let columnIndex = 1; columnIndex <= set1.length; columnIndex += 1) {\n      if (set1[columnIndex - 1] === set2[rowIndex - 1]) {\n        lcsMatrix[rowIndex][columnIndex] = lcsMatrix[rowIndex - 1][columnIndex - 1] + 1;\n      } else {\n        lcsMatrix[rowIndex][columnIndex] = Math.max(\n          lcsMatrix[rowIndex - 1][columnIndex],\n          lcsMatrix[rowIndex][columnIndex - 1],\n        );\n      }\n    }\n  }\n\n  // Calculate LCS based on LCS matrix.\n  if (!lcsMatrix[set2.length][set1.length]) {\n    // If the length of largest common string is zero then return empty string.\n    return [''];\n  }\n\n  const longestSequence = [];\n  let columnIndex = set1.length;\n  let rowIndex = set2.length;\n\n  while (columnIndex > 0 || rowIndex > 0) {\n    if (set1[columnIndex - 1] === set2[rowIndex - 1]) {\n      // Move by diagonal left-top.\n      longestSequence.unshift(set1[columnIndex - 1]);\n      columnIndex -= 1;\n      rowIndex -= 1;\n    } else if (lcsMatrix[rowIndex][columnIndex] === lcsMatrix[rowIndex][columnIndex - 1]) {\n      // Move left.\n      columnIndex -= 1;\n    } else {\n      // Move up.\n      rowIndex -= 1;\n    }\n  }\n\n  return longestSequence;\n}\n"
  },
  {
    "path": "src/algorithms/sets/longest-common-subsequence/longestCommonSubsequenceRecursive.js",
    "content": "/* eslint-disable no-param-reassign */\n/**\n * Longest Common Subsequence (LCS) (Recursive Approach).\n *\n * @param {string} string1\n * @param {string} string2\n * @return {number}\n */\nexport default function longestCommonSubsequenceRecursive(string1, string2) {\n  /**\n   *\n   * @param {string} s1\n   * @param {string} s2\n   * @return {string} - returns the LCS (Longest Common Subsequence)\n   */\n  const lcs = (s1, s2, memo = {}) => {\n    if (!s1 || !s2) return '';\n\n    if (memo[`${s1}:${s2}`]) return memo[`${s1}:${s2}`];\n\n    if (s1[0] === s2[0]) {\n      return s1[0] + lcs(s1.substring(1), s2.substring(1), memo);\n    }\n\n    const nextLcs1 = lcs(s1.substring(1), s2, memo);\n    const nextLcs2 = lcs(s1, s2.substring(1), memo);\n\n    const nextLongest = nextLcs1.length >= nextLcs2.length ? nextLcs1 : nextLcs2;\n\n    memo[`${s1}:${s2}`] = nextLongest;\n\n    return nextLongest;\n  };\n\n  return lcs(string1, string2);\n}\n"
  },
  {
    "path": "src/algorithms/sets/longest-increasing-subsequence/README.md",
    "content": "# Longest Increasing Subsequence\n\nThe longest increasing subsequence problem is to find a subsequence of a \ngiven sequence in which the subsequence's elements are in sorted order, \nlowest to highest, and in which the subsequence is as long as possible. \nThis subsequence is not necessarily contiguous, or unique. \n\n## Complexity\n\nThe longest increasing subsequence problem is solvable in \ntime `O(n log n)`, where `n` denotes the length of the input sequence.\n\nDynamic programming approach has complexity `O(n * n)`.\n\n## Example\n\nIn the first 16 terms of the binary Van der Corput sequence\n\n```\n0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15\n```\n\na longest increasing subsequence is\n\n```\n0, 2, 6, 9, 11, 15.\n```\n\nThis subsequence has length six; \nthe input sequence has no seven-member increasing subsequences. \nThe longest increasing subsequence in this example is not unique: for \ninstance,\n\n```\n0, 4, 6, 9, 11, 15 or\n0, 2, 6, 9, 13, 15 or\n0, 4, 6, 9, 13, 15\n```\n\nare other increasing subsequences of equal length in the same \ninput sequence.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Longest_increasing_subsequence)\n- [Dynamic Programming Approach on YouTube](https://www.youtube.com/watch?v=CE2b_-XfVDk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sets/longest-increasing-subsequence/__test__/dpLongestIncreasingSubsequence.test.js",
    "content": "import dpLongestIncreasingSubsequence from '../dpLongestIncreasingSubsequence';\n\ndescribe('dpLongestIncreasingSubsequence', () => {\n  it('should find longest increasing subsequence length', () => {\n    // Should be:\n    // 9 or\n    // 8 or\n    // 7 or\n    // 6 or\n    // ...\n    expect(dpLongestIncreasingSubsequence([\n      9, 8, 7, 6, 5, 4, 3, 2, 1, 0,\n    ])).toBe(1);\n\n    // Should be:\n    // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9\n    expect(dpLongestIncreasingSubsequence([\n      0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n    ])).toBe(10);\n\n    // Should be:\n    // -1, 0, 2, 3\n    expect(dpLongestIncreasingSubsequence([\n      3, 4, -1, 0, 6, 2, 3,\n    ])).toBe(4);\n\n    // Should be:\n    // 0, 2, 6, 9, 11, 15 or\n    // 0, 4, 6, 9, 11, 15 or\n    // 0, 2, 6, 9, 13, 15 or\n    // 0, 4, 6, 9, 13, 15\n    expect(dpLongestIncreasingSubsequence([\n      0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15,\n    ])).toBe(6);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/longest-increasing-subsequence/dpLongestIncreasingSubsequence.js",
    "content": "/**\n * Dynamic programming approach to find longest increasing subsequence.\n * Complexity: O(n * n)\n *\n * @param {number[]} sequence\n * @return {number}\n */\nexport default function dpLongestIncreasingSubsequence(sequence) {\n  // Create array with longest increasing substrings length and\n  // fill it with 1-s that would mean that each element of the sequence\n  // is itself a minimum increasing subsequence.\n  const lengthsArray = Array(sequence.length).fill(1);\n\n  let previousElementIndex = 0;\n  let currentElementIndex = 1;\n\n  while (currentElementIndex < sequence.length) {\n    if (sequence[previousElementIndex] < sequence[currentElementIndex]) {\n      // If current element is bigger then the previous one then\n      // current element is a part of increasing subsequence which\n      // length is by one bigger then the length of increasing subsequence\n      // for previous element.\n      const newLength = lengthsArray[previousElementIndex] + 1;\n      if (newLength > lengthsArray[currentElementIndex]) {\n        // Increase only if previous element would give us bigger subsequence length\n        // then we already have for current element.\n        lengthsArray[currentElementIndex] = newLength;\n      }\n    }\n\n    // Move previous element index right.\n    previousElementIndex += 1;\n\n    // If previous element index equals to current element index then\n    // shift current element right and reset previous element index to zero.\n    if (previousElementIndex === currentElementIndex) {\n      currentElementIndex += 1;\n      previousElementIndex = 0;\n    }\n  }\n\n  // Find the biggest element in lengthsArray.\n  // This number is the biggest length of increasing subsequence.\n  let longestIncreasingLength = 0;\n\n  for (let i = 0; i < lengthsArray.length; i += 1) {\n    if (lengthsArray[i] > longestIncreasingLength) {\n      longestIncreasingLength = lengthsArray[i];\n    }\n  }\n\n  return longestIncreasingLength;\n}\n"
  },
  {
    "path": "src/algorithms/sets/maximum-subarray/README.md",
    "content": "# Maximum subarray problem\n\nThe maximum subarray problem is the task of finding the contiguous\nsubarray within a one-dimensional array, `a[1...n]`, of numbers\nwhich has the largest sum, where,\n\n![Maximum subarray](https://wikimedia.org/api/rest_v1/media/math/render/svg/e8960f093107b71b21827e726e2bad8b023779b2)\n\n![Maximum subarray](https://www.geeksforgeeks.org/wp-content/uploads/kadane-Algorithm.png)\n\n## Example\n\nThe list usually contains both positive and negative numbers along\nwith `0`. For example, for the array of\nvalues `−2, 1, −3, 4, −1, 2, 1, −5, 4` the contiguous subarray\nwith the largest sum is `4, −1, 2, 1`, with sum `6`.\n\n## Solutions\n\n- Brute Force solution `O(n^2)`: [bfMaximumSubarray.js](./bfMaximumSubarray.js)\n- Divide and Conquer solution `O(n^2)`: [dcMaximumSubarraySum.js](./dcMaximumSubarraySum.js)\n- Dynamic Programming solution `O(n)`: [dpMaximumSubarray.js](./dpMaximumSubarray.js)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Maximum_subarray_problem)\n- [YouTube](https://www.youtube.com/watch?v=ohHWQf1HDfU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/)\n- [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)\n"
  },
  {
    "path": "src/algorithms/sets/maximum-subarray/__test__/bfMaximumSubarray.test.js",
    "content": "import bfMaximumSubarray from '../bfMaximumSubarray';\n\ndescribe('bfMaximumSubarray', () => {\n  it('should find maximum subarray using the brute force algorithm', () => {\n    expect(bfMaximumSubarray([])).toEqual([]);\n    expect(bfMaximumSubarray([0, 0])).toEqual([0]);\n    expect(bfMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]);\n    expect(bfMaximumSubarray([0, 0, 1, 2])).toEqual([0, 0, 1, 2]);\n    expect(bfMaximumSubarray([0, 0, -1, 2])).toEqual([2]);\n    expect(bfMaximumSubarray([-1, -2, -3, -4, -5])).toEqual([-1]);\n    expect(bfMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual([1, 2, 3, 2, 3, 4, 5]);\n    expect(bfMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual([4, -1, 2, 1]);\n    expect(bfMaximumSubarray([-2, -3, 4, -1, -2, 1, 5, -3])).toEqual([4, -1, -2, 1, 5]);\n    expect(bfMaximumSubarray([1, -3, 2, -5, 7, 6, -1, 4, 11, -23])).toEqual([7, 6, -1, 4, 11]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/maximum-subarray/__test__/dcMaximumSubarraySum.test.js",
    "content": "import dcMaximumSubarray from '../dcMaximumSubarraySum';\n\ndescribe('dcMaximumSubarraySum', () => {\n  it('should find maximum subarray sum using the divide and conquer algorithm', () => {\n    expect(dcMaximumSubarray([])).toEqual(-Infinity);\n    expect(dcMaximumSubarray([0, 0])).toEqual(0);\n    expect(dcMaximumSubarray([0, 0, 1])).toEqual(1);\n    expect(dcMaximumSubarray([0, 0, 1, 2])).toEqual(3);\n    expect(dcMaximumSubarray([0, 0, -1, 2])).toEqual(2);\n    expect(dcMaximumSubarray([-1, -2, -3, -4, -5])).toEqual(-1);\n    expect(dcMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual(20);\n    expect(dcMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual(6);\n    expect(dcMaximumSubarray([-2, -3, 4, -1, -2, 1, 5, -3])).toEqual(7);\n    expect(dcMaximumSubarray([1, -3, 2, -5, 7, 6, -1, 4, 11, -23])).toEqual(27);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/maximum-subarray/__test__/dpMaximumSubarray.test.js",
    "content": "import dpMaximumSubarray from '../dpMaximumSubarray';\n\ndescribe('dpMaximumSubarray', () => {\n  it('should find maximum subarray using the dynamic programming algorithm', () => {\n    expect(dpMaximumSubarray([])).toEqual([]);\n    expect(dpMaximumSubarray([0, 0])).toEqual([0]);\n    expect(dpMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]);\n    expect(dpMaximumSubarray([0, 0, 1, 2])).toEqual([0, 0, 1, 2]);\n    expect(dpMaximumSubarray([0, 0, -1, 2])).toEqual([2]);\n    expect(dpMaximumSubarray([-1, -2, -3, -4, -5])).toEqual([-1]);\n    expect(dpMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual([1, 2, 3, 2, 3, 4, 5]);\n    expect(dpMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual([4, -1, 2, 1]);\n    expect(dpMaximumSubarray([-2, -3, 4, -1, -2, 1, 5, -3])).toEqual([4, -1, -2, 1, 5]);\n    expect(dpMaximumSubarray([1, -3, 2, -5, 7, 6, -1, 4, 11, -23])).toEqual([7, 6, -1, 4, 11]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/maximum-subarray/bfMaximumSubarray.js",
    "content": "/**\n * Brute Force solution.\n * Complexity: O(n^2)\n *\n * @param {Number[]} inputArray\n * @return {Number[]}\n */\nexport default function bfMaximumSubarray(inputArray) {\n  let maxSubarrayStartIndex = 0;\n  let maxSubarrayLength = 0;\n  let maxSubarraySum = null;\n\n  for (let startIndex = 0; startIndex < inputArray.length; startIndex += 1) {\n    let subarraySum = 0;\n    for (let arrLength = 1; arrLength <= (inputArray.length - startIndex); arrLength += 1) {\n      subarraySum += inputArray[startIndex + (arrLength - 1)];\n      if (maxSubarraySum === null || subarraySum > maxSubarraySum) {\n        maxSubarraySum = subarraySum;\n        maxSubarrayStartIndex = startIndex;\n        maxSubarrayLength = arrLength;\n      }\n    }\n  }\n\n  return inputArray.slice(maxSubarrayStartIndex, maxSubarrayStartIndex + maxSubarrayLength);\n}\n"
  },
  {
    "path": "src/algorithms/sets/maximum-subarray/dcMaximumSubarraySum.js",
    "content": "/**\n * Divide and Conquer solution.\n * Complexity: O(n^2) in case if no memoization applied\n *\n * @param {Number[]} inputArray\n * @return {Number[]}\n */\nexport default function dcMaximumSubarraySum(inputArray) {\n  /**\n   * We are going through the inputArray array and for each element we have two options:\n   * - to pick\n   * - not to pick\n   *\n   * Also keep in mind, that the maximum sub-array must be contiguous. It means if we picked\n   * the element, we need to continue picking the next elements or stop counting the max sum.\n   *\n   * @param {number} elementIndex - the index of the element we're deciding to pick or not\n   * @param {boolean} mustPick - to pick or not to pick the element\n   * @returns {number} - maximum subarray sum that we'll get\n   */\n  function solveRecursively(elementIndex, mustPick) {\n    if (elementIndex >= inputArray.length) {\n      return mustPick ? 0 : -Infinity;\n    }\n    return Math.max(\n      // Option #1: Pick the current element, and continue picking next one.\n      inputArray[elementIndex] + solveRecursively(elementIndex + 1, true),\n      // Option #2: Don't pick the current element.\n      mustPick ? 0 : solveRecursively(elementIndex + 1, false),\n    );\n  }\n  return solveRecursively(0, false);\n}\n"
  },
  {
    "path": "src/algorithms/sets/maximum-subarray/dpMaximumSubarray.js",
    "content": "/**\n * Dynamic Programming solution.\n * Complexity: O(n)\n *\n * @param {Number[]} inputArray\n * @return {Number[]}\n */\nexport default function dpMaximumSubarray(inputArray) {\n  // We iterate through the inputArray once, using a greedy approach to keep track of the maximum\n  // sum we've seen so far and the current sum.\n  //\n  // The currentSum variable gets reset to 0 every time it drops below 0.\n  //\n  // The maxSum variable is set to -Infinity so that if all numbers are negative, the highest\n  // negative number will constitute the maximum subarray.\n\n  let maxSum = -Infinity;\n  let currentSum = 0;\n\n  // We need to keep track of the starting and ending indices that contributed to our maxSum\n  // so that we can return the actual subarray. From the beginning let's assume that whole array\n  // is contributing to maxSum.\n  let maxStartIndex = 0;\n  let maxEndIndex = inputArray.length - 1;\n  let currentStartIndex = 0;\n\n  inputArray.forEach((currentNumber, currentIndex) => {\n    currentSum += currentNumber;\n\n    // Update maxSum and the corresponding indices if we have found a new max.\n    if (maxSum < currentSum) {\n      maxSum = currentSum;\n      maxStartIndex = currentStartIndex;\n      maxEndIndex = currentIndex;\n    }\n\n    // Reset currentSum and currentStartIndex if currentSum drops below 0.\n    if (currentSum < 0) {\n      currentSum = 0;\n      currentStartIndex = currentIndex + 1;\n    }\n  });\n\n  return inputArray.slice(maxStartIndex, maxEndIndex + 1);\n}\n"
  },
  {
    "path": "src/algorithms/sets/permutations/README.md",
    "content": "# Permutations\n\nWhen the order doesn't matter, it is a **Combination**.\n\nWhen the order **does** matter it is a **Permutation**.\n\n**\"The combination to the safe is 472\"**. We do care about the order. `724` won't work, nor will `247`.\nIt has to be exactly `4-7-2`.\n\n## Permutations without repetitions\n\nA permutation, also called an “arrangement number” or “order”, is a rearrangement of\nthe elements of an ordered list `S` into a one-to-one correspondence with `S` itself.\n\nBelow are the permutations of string `ABC`.\n\n`ABC ACB BAC BCA CBA CAB`\n\nOr for example the first three people in a running race: you can't be first and second.\n\n**Number of combinations**\n\n```\nn * (n-1) * (n -2) * ... * 1 = n!\n```\n\n## Permutations with repetitions\n\nWhen repetition is allowed we have permutations with repetitions.\nFor example the the lock below: it could be `333`.\n\n![Permutation Lock](https://www.mathsisfun.com/combinatorics/images/combination-lock.jpg)\n\n**Number of combinations**\n\n```\nn * n * n ... (r times) = n^r\n```\n\n## Cheatsheet\n\n![Permutations and Combinations Overview](./images/overview.png)\n\n![Permutations overview](./images/permutations-overview.jpeg)\n\n| | |\n| --- | --- |\n|![Permutations with repetition](./images/permutations-with-repetitions.jpg) | ![Permutations without repetition](./images/permutations-without-repetitions.jpg) |\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Math Is Fun](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)\n- [Permutations/combinations cheat sheets](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)\n"
  },
  {
    "path": "src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js",
    "content": "import permutateWithRepetitions from '../permutateWithRepetitions';\n\ndescribe('permutateWithRepetitions', () => {\n  it('should permutate string with repetition', () => {\n    const permutations1 = permutateWithRepetitions(['A']);\n    expect(permutations1).toEqual([\n      ['A'],\n    ]);\n\n    const permutations2 = permutateWithRepetitions(['A', 'B']);\n    expect(permutations2).toEqual([\n      ['A', 'A'],\n      ['A', 'B'],\n      ['B', 'A'],\n      ['B', 'B'],\n    ]);\n\n    const permutations3 = permutateWithRepetitions(['A', 'B', 'C']);\n    expect(permutations3).toEqual([\n      ['A', 'A', 'A'],\n      ['A', 'A', 'B'],\n      ['A', 'A', 'C'],\n      ['A', 'B', 'A'],\n      ['A', 'B', 'B'],\n      ['A', 'B', 'C'],\n      ['A', 'C', 'A'],\n      ['A', 'C', 'B'],\n      ['A', 'C', 'C'],\n      ['B', 'A', 'A'],\n      ['B', 'A', 'B'],\n      ['B', 'A', 'C'],\n      ['B', 'B', 'A'],\n      ['B', 'B', 'B'],\n      ['B', 'B', 'C'],\n      ['B', 'C', 'A'],\n      ['B', 'C', 'B'],\n      ['B', 'C', 'C'],\n      ['C', 'A', 'A'],\n      ['C', 'A', 'B'],\n      ['C', 'A', 'C'],\n      ['C', 'B', 'A'],\n      ['C', 'B', 'B'],\n      ['C', 'B', 'C'],\n      ['C', 'C', 'A'],\n      ['C', 'C', 'B'],\n      ['C', 'C', 'C'],\n    ]);\n\n    const permutations4 = permutateWithRepetitions(['A', 'B', 'C', 'D']);\n    expect(permutations4.length).toBe(4 * 4 * 4 * 4);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/permutations/__test__/permutateWithoutRepetitions.test.js",
    "content": "import permutateWithoutRepetitions from '../permutateWithoutRepetitions';\nimport factorial from '../../../math/factorial/factorial';\n\ndescribe('permutateWithoutRepetitions', () => {\n  it('should permutate string', () => {\n    const permutations1 = permutateWithoutRepetitions(['A']);\n    expect(permutations1).toEqual([\n      ['A'],\n    ]);\n\n    const permutations2 = permutateWithoutRepetitions(['A', 'B']);\n    expect(permutations2.length).toBe(2);\n    expect(permutations2).toEqual([\n      ['A', 'B'],\n      ['B', 'A'],\n    ]);\n\n    const permutations6 = permutateWithoutRepetitions(['A', 'A']);\n    expect(permutations6.length).toBe(2);\n    expect(permutations6).toEqual([\n      ['A', 'A'],\n      ['A', 'A'],\n    ]);\n\n    const permutations3 = permutateWithoutRepetitions(['A', 'B', 'C']);\n    expect(permutations3.length).toBe(factorial(3));\n    expect(permutations3).toEqual([\n      ['A', 'B', 'C'],\n      ['B', 'A', 'C'],\n      ['B', 'C', 'A'],\n      ['A', 'C', 'B'],\n      ['C', 'A', 'B'],\n      ['C', 'B', 'A'],\n    ]);\n\n    const permutations4 = permutateWithoutRepetitions(['A', 'B', 'C', 'D']);\n    expect(permutations4.length).toBe(factorial(4));\n    expect(permutations4).toEqual([\n      ['A', 'B', 'C', 'D'],\n      ['B', 'A', 'C', 'D'],\n      ['B', 'C', 'A', 'D'],\n      ['B', 'C', 'D', 'A'],\n      ['A', 'C', 'B', 'D'],\n      ['C', 'A', 'B', 'D'],\n      ['C', 'B', 'A', 'D'],\n      ['C', 'B', 'D', 'A'],\n      ['A', 'C', 'D', 'B'],\n      ['C', 'A', 'D', 'B'],\n      ['C', 'D', 'A', 'B'],\n      ['C', 'D', 'B', 'A'],\n      ['A', 'B', 'D', 'C'],\n      ['B', 'A', 'D', 'C'],\n      ['B', 'D', 'A', 'C'],\n      ['B', 'D', 'C', 'A'],\n      ['A', 'D', 'B', 'C'],\n      ['D', 'A', 'B', 'C'],\n      ['D', 'B', 'A', 'C'],\n      ['D', 'B', 'C', 'A'],\n      ['A', 'D', 'C', 'B'],\n      ['D', 'A', 'C', 'B'],\n      ['D', 'C', 'A', 'B'],\n      ['D', 'C', 'B', 'A'],\n    ]);\n\n    const permutations5 = permutateWithoutRepetitions(['A', 'B', 'C', 'D', 'E', 'F']);\n    expect(permutations5.length).toBe(factorial(6));\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/permutations/permutateWithRepetitions.js",
    "content": "/**\n * @param {*[]} permutationOptions\n * @param {number} permutationLength\n * @return {*[]}\n */\nexport default function permutateWithRepetitions(\n  permutationOptions,\n  permutationLength = permutationOptions.length,\n) {\n  if (permutationLength === 1) {\n    return permutationOptions.map((permutationOption) => [permutationOption]);\n  }\n\n  // Init permutations array.\n  const permutations = [];\n\n  // Get smaller permutations.\n  const smallerPermutations = permutateWithRepetitions(\n    permutationOptions,\n    permutationLength - 1,\n  );\n\n  // Go through all options and join it to the smaller permutations.\n  permutationOptions.forEach((currentOption) => {\n    smallerPermutations.forEach((smallerPermutation) => {\n      permutations.push([currentOption].concat(smallerPermutation));\n    });\n  });\n\n  return permutations;\n}\n"
  },
  {
    "path": "src/algorithms/sets/permutations/permutateWithoutRepetitions.js",
    "content": "/**\n * @param {*[]} permutationOptions\n * @return {*[]}\n */\nexport default function permutateWithoutRepetitions(permutationOptions) {\n  if (permutationOptions.length === 1) {\n    return [permutationOptions];\n  }\n\n  // Init permutations array.\n  const permutations = [];\n\n  // Get all permutations for permutationOptions excluding the first element.\n  const smallerPermutations = permutateWithoutRepetitions(permutationOptions.slice(1));\n\n  // Insert first option into every possible position of every smaller permutation.\n  const firstOption = permutationOptions[0];\n\n  for (let permIndex = 0; permIndex < smallerPermutations.length; permIndex += 1) {\n    const smallerPermutation = smallerPermutations[permIndex];\n\n    // Insert first option into every possible position of smallerPermutation.\n    for (let positionIndex = 0; positionIndex <= smallerPermutation.length; positionIndex += 1) {\n      const permutationPrefix = smallerPermutation.slice(0, positionIndex);\n      const permutationSuffix = smallerPermutation.slice(positionIndex);\n      permutations.push(permutationPrefix.concat([firstOption], permutationSuffix));\n    }\n  }\n\n  return permutations;\n}\n"
  },
  {
    "path": "src/algorithms/sets/power-set/README.md",
    "content": "# Power Set\n\nPower set of a set `S` is the set of all of the subsets of `S`, including the\nempty set and `S` itself. Power set of set `S` is denoted as `P(S)`.\n\nFor example for `{x, y, z}`, the subsets\nare:\n\n```text\n{\n  {}, // (also denoted empty set ∅ or the null set)\n  {x},\n  {y},\n  {z},\n  {x, y},\n  {x, z},\n  {y, z},\n  {x, y, z}\n}\n```\n\n![Power Set](https://www.mathsisfun.com/sets/images/power-set.svg)\n\nHere is how we may illustrate the elements of the power set of the set `{x, y, z}` ordered with respect to\ninclusion:\n\n![](https://upload.wikimedia.org/wikipedia/commons/e/ea/Hasse_diagram_of_powerset_of_3.svg)\n\n**Number of Subsets**\n\nIf `S` is a finite set with `|S| = n` elements, then the number of subsets\nof `S` is `|P(S)| = 2^n`. This fact, which is the motivation for the\nnotation `2^S`, may be demonstrated simply as follows:\n\n> First, order the elements of `S` in any manner. We write any subset of `S` in\nthe format `{γ1, γ2, ..., γn}` where `γi , 1 ≤ i ≤ n`, can take the value\nof `0` or `1`. If `γi = 1`, the `i`-th element of `S` is in the subset;\notherwise, the `i`-th element is not in the subset. Clearly the number of\ndistinct subsets that can be constructed this way is `2^n` as `γi ∈ {0, 1}`.\n\n## Algorithms\n\n### Bitwise Solution\n\nEach number in binary representation in a range from `0` to `2^n` does exactly\nwhat we need: it shows by its bits (`0` or `1`) whether to include related\nelement from the set or not. For example, for the set `{1, 2, 3}` the binary\nnumber of `0b010` would mean that we need to include only `2` to the current set.\n\n|       | `abc` | Subset        |\n| :---: | :---: | :-----------: |\n| `0`   | `000` | `{}`          |\n| `1`   | `001` | `{c}`         |\n| `2`   | `010` | `{b}`         |\n| `3`   | `011` | `{c, b}`      |\n| `4`   | `100` | `{a}`         |\n| `5`   | `101` | `{a, c}`      |\n| `6`   | `110` | `{a, b}`      |\n| `7`   | `111` | `{a, b, c}`   |\n\n> See [bwPowerSet.js](./bwPowerSet.js) file for bitwise solution.\n\n### Backtracking Solution\n\nIn backtracking approach we're constantly trying to add next element of the set\nto the subset, memorizing it and then removing it and try the same with the next\nelement.\n\n> See [btPowerSet.js](./btPowerSet.js) file for backtracking solution.\n\n### Cascading Solution\n\nThis is, arguably, the simplest solution to generate a Power Set.\n\nWe start with an empty set:\n\n```text\npowerSets = [[]]\n```\n\nNow, let's say:\n\n```text\noriginalSet = [1, 2, 3]\n```\n\nLet's add the 1st element from the originalSet to all existing sets:\n\n```text\n[[]] ← 1 = [[], [1]]\n```\n\nAdding the 2nd element to all existing sets:\n\n```text\n[[], [1]] ← 2 = [[], [1], [2], [1, 2]]\n```\n\nAdding the 3nd element to all existing sets:\n\n```\n[[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]\n```\n\nAnd 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.\n\n> See [caPowerSet.js](./caPowerSet.js) file for cascading solution.\n\n## References\n\n* [Wikipedia](https://en.wikipedia.org/wiki/Power_set)\n* [Math is Fun](https://www.mathsisfun.com/sets/power-set.html)\n"
  },
  {
    "path": "src/algorithms/sets/power-set/__test__/btPowerSet.test.js",
    "content": "import btPowerSet from '../btPowerSet';\n\ndescribe('btPowerSet', () => {\n  it('should calculate power set of given set using backtracking approach', () => {\n    expect(btPowerSet([1])).toEqual([\n      [],\n      [1],\n    ]);\n\n    expect(btPowerSet([1, 2, 3])).toEqual([\n      [],\n      [1],\n      [1, 2],\n      [1, 2, 3],\n      [1, 3],\n      [2],\n      [2, 3],\n      [3],\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/power-set/__test__/bwPowerSet.test.js",
    "content": "import bwPowerSet from '../bwPowerSet';\n\ndescribe('bwPowerSet', () => {\n  it('should calculate power set of given set using bitwise approach', () => {\n    expect(bwPowerSet([1])).toEqual([\n      [],\n      [1],\n    ]);\n\n    expect(bwPowerSet([1, 2, 3])).toEqual([\n      [],\n      [1],\n      [2],\n      [1, 2],\n      [3],\n      [1, 3],\n      [2, 3],\n      [1, 2, 3],\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/power-set/__test__/caPowerSet.test.js",
    "content": "import caPowerSet from '../caPowerSet';\n\ndescribe('caPowerSet', () => {\n  it('should calculate power set of given set using cascading approach', () => {\n    expect(caPowerSet([1])).toEqual([\n      [],\n      [1],\n    ]);\n\n    expect(caPowerSet([1, 2])).toEqual([\n      [],\n      [1],\n      [2],\n      [1, 2],\n    ]);\n\n    expect(caPowerSet([1, 2, 3])).toEqual([\n      [],\n      [1],\n      [2],\n      [1, 2],\n      [3],\n      [1, 3],\n      [2, 3],\n      [1, 2, 3],\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/power-set/btPowerSet.js",
    "content": "/**\n * @param {*[]} originalSet - Original set of elements we're forming power-set of.\n * @param {*[][]} allSubsets - All subsets that have been formed so far.\n * @param {*[]} currentSubSet - Current subset that we're forming at the moment.\n * @param {number} startAt - The position of in original set we're starting to form current subset.\n * @return {*[][]} - All subsets of original set.\n */\nfunction btPowerSetRecursive(originalSet, allSubsets = [[]], currentSubSet = [], startAt = 0) {\n  // Let's iterate over originalSet elements that may be added to the subset\n  // without having duplicates. The value of startAt prevents adding the duplicates.\n  for (let position = startAt; position < originalSet.length; position += 1) {\n    // Let's push current element to the subset\n    currentSubSet.push(originalSet[position]);\n\n    // Current subset is already valid so let's memorize it.\n    // We do array destruction here to save the clone of the currentSubSet.\n    // We need to save a clone since the original currentSubSet is going to be\n    // mutated in further recursive calls.\n    allSubsets.push([...currentSubSet]);\n\n    // Let's try to generate all other subsets for the current subset.\n    // We're increasing the position by one to avoid duplicates in subset.\n    btPowerSetRecursive(originalSet, allSubsets, currentSubSet, position + 1);\n\n    // BACKTRACK. Exclude last element from the subset and try the next valid one.\n    currentSubSet.pop();\n  }\n\n  // Return all subsets of a set.\n  return allSubsets;\n}\n\n/**\n * Find power-set of a set using BACKTRACKING approach.\n *\n * @param {*[]} originalSet\n * @return {*[][]}\n */\nexport default function btPowerSet(originalSet) {\n  return btPowerSetRecursive(originalSet);\n}\n"
  },
  {
    "path": "src/algorithms/sets/power-set/bwPowerSet.js",
    "content": "/**\n * Find power-set of a set using BITWISE approach.\n *\n * @param {*[]} originalSet\n * @return {*[][]}\n */\nexport default function bwPowerSet(originalSet) {\n  const subSets = [];\n\n  // We will have 2^n possible combinations (where n is a length of original set).\n  // It is because for every element of original set we will decide whether to include\n  // it or not (2 options for each set element).\n  const numberOfCombinations = 2 ** originalSet.length;\n\n  // Each number in binary representation in a range from 0 to 2^n does exactly what we need:\n  // it shows by its bits (0 or 1) whether to include related element from the set or not.\n  // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to\n  // include only \"2\" to the current set.\n  for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {\n    const subSet = [];\n\n    for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {\n      // Decide whether we need to include current element into the subset or not.\n      if (combinationIndex & (1 << setElementIndex)) {\n        subSet.push(originalSet[setElementIndex]);\n      }\n    }\n\n    // Add current subset to the list of all subsets.\n    subSets.push(subSet);\n  }\n\n  return subSets;\n}\n"
  },
  {
    "path": "src/algorithms/sets/power-set/caPowerSet.js",
    "content": "/**\n * Find power-set of a set using CASCADING approach.\n *\n * @param {*[]} originalSet\n * @return {*[][]}\n */\nexport default function caPowerSet(originalSet) {\n  // Let's start with an empty set.\n  const sets = [[]];\n\n  /*\n    Now, let's say:\n    originalSet = [1, 2, 3].\n\n    Let's add the first element from the originalSet to all existing sets:\n    [[]] ← 1 = [[], [1]]\n\n    Adding the 2nd element to all existing sets:\n    [[], [1]] ← 2 = [[], [1], [2], [1, 2]]\n\n    Adding the 3nd element to all existing sets:\n    [[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]\n\n    And so on for the rest of the elements from originalSet.\n    On every iteration the number of sets is doubled, so we'll get 2^n sets.\n  */\n  for (let numIdx = 0; numIdx < originalSet.length; numIdx += 1) {\n    const existingSetsNum = sets.length;\n\n    for (let setIdx = 0; setIdx < existingSetsNum; setIdx += 1) {\n      const set = [...sets[setIdx], originalSet[numIdx]];\n      sets.push(set);\n    }\n  }\n\n  return sets;\n}\n"
  },
  {
    "path": "src/algorithms/sets/shortest-common-supersequence/README.md",
    "content": "# Shortest Common Supersequence\n\nThe shortest common supersequence (SCS) of two sequences `X` and `Y` \nis the shortest sequence which has `X` and `Y` as subsequences.\n\nIn other words assume we're given two strings str1 and str2, find \nthe shortest string that has both str1 and str2 as subsequences.\n\nThis is a problem closely related to the longest common \nsubsequence problem.\n\n## Example\n\n```\nInput:   str1 = \"geek\",  str2 = \"eke\"\nOutput: \"geeke\"\n\nInput:   str1 = \"AGGTAB\",  str2 = \"GXTXAYB\"\nOutput:  \"AGXGTXAYB\"\n```\n\n## References\n\n- [GeeksForGeeks](https://www.geeksforgeeks.org/shortest-common-supersequence/)\n"
  },
  {
    "path": "src/algorithms/sets/shortest-common-supersequence/__test__/shortestCommonSupersequence.test.js",
    "content": "import shortestCommonSupersequence from '../shortestCommonSupersequence';\n\ndescribe('shortestCommonSupersequence', () => {\n  it('should find shortest common supersequence of two sequences', () => {\n    // LCS (longest common subsequence) is empty\n    expect(shortestCommonSupersequence(\n      ['A', 'B', 'C'],\n      ['D', 'E', 'F'],\n    )).toEqual(['A', 'B', 'C', 'D', 'E', 'F']);\n\n    // LCS (longest common subsequence) is \"EE\"\n    expect(shortestCommonSupersequence(\n      ['G', 'E', 'E', 'K'],\n      ['E', 'K', 'E'],\n    )).toEqual(['G', 'E', 'K', 'E', 'K']);\n\n    // LCS (longest common subsequence) is \"GTAB\"\n    expect(shortestCommonSupersequence(\n      ['A', 'G', 'G', 'T', 'A', 'B'],\n      ['G', 'X', 'T', 'X', 'A', 'Y', 'B'],\n    )).toEqual(['A', 'G', 'G', 'X', 'T', 'X', 'A', 'Y', 'B']);\n\n    // LCS (longest common subsequence) is \"BCBA\".\n    expect(shortestCommonSupersequence(\n      ['A', 'B', 'C', 'B', 'D', 'A', 'B'],\n      ['B', 'D', 'C', 'A', 'B', 'A'],\n    )).toEqual(['A', 'B', 'D', 'C', 'A', 'B', 'D', 'A', 'B']);\n\n    // LCS (longest common subsequence) is \"BDABA\".\n    expect(shortestCommonSupersequence(\n      ['B', 'D', 'C', 'A', 'B', 'A'],\n      ['A', 'B', 'C', 'B', 'D', 'A', 'B', 'A', 'C'],\n    )).toEqual(['A', 'B', 'C', 'B', 'D', 'C', 'A', 'B', 'A', 'C']);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sets/shortest-common-supersequence/shortestCommonSupersequence.js",
    "content": "import longestCommonSubsequence from '../longest-common-subsequence/longestCommonSubsequence';\n\n/**\n * @param {string[]} set1\n * @param {string[]} set2\n * @return {string[]}\n */\n\nexport default function shortestCommonSupersequence(set1, set2) {\n  // Let's first find the longest common subsequence of two sets.\n  const lcs = longestCommonSubsequence(set1, set2);\n\n  // If LCS is empty then the shortest common supersequence would be just\n  // concatenation of two sequences.\n  if (lcs.length === 1 && lcs[0] === '') {\n    return set1.concat(set2);\n  }\n\n  // Now let's add elements of set1 and set2 in order before/inside/after the LCS.\n  let supersequence = [];\n\n  let setIndex1 = 0;\n  let setIndex2 = 0;\n  let lcsIndex = 0;\n  let setOnHold1 = false;\n  let setOnHold2 = false;\n\n  while (lcsIndex < lcs.length) {\n    // Add elements of the first set to supersequence in correct order.\n    if (setIndex1 < set1.length) {\n      if (!setOnHold1 && set1[setIndex1] !== lcs[lcsIndex]) {\n        supersequence.push(set1[setIndex1]);\n        setIndex1 += 1;\n      } else {\n        setOnHold1 = true;\n      }\n    }\n\n    // Add elements of the second set to supersequence in correct order.\n    if (setIndex2 < set2.length) {\n      if (!setOnHold2 && set2[setIndex2] !== lcs[lcsIndex]) {\n        supersequence.push(set2[setIndex2]);\n        setIndex2 += 1;\n      } else {\n        setOnHold2 = true;\n      }\n    }\n\n    // Add LCS element to the supersequence in correct order.\n    if (setOnHold1 && setOnHold2) {\n      supersequence.push(lcs[lcsIndex]);\n      lcsIndex += 1;\n      setIndex1 += 1;\n      setIndex2 += 1;\n      setOnHold1 = false;\n      setOnHold2 = false;\n    }\n  }\n\n  // Attach set1 leftovers.\n  if (setIndex1 < set1.length) {\n    supersequence = supersequence.concat(set1.slice(setIndex1));\n  }\n\n  // Attach set2 leftovers.\n  if (setIndex2 < set2.length) {\n    supersequence = supersequence.concat(set2.slice(setIndex2));\n  }\n\n  return supersequence;\n}\n"
  },
  {
    "path": "src/algorithms/sorting/Sort.js",
    "content": "import Comparator from '../../utils/comparator/Comparator';\n\n/**\n * @typedef {Object} SorterCallbacks\n * @property {function(a: *, b: *)} compareCallback - If provided then all elements comparisons\n *  will be done through this callback.\n * @property {function(a: *)} visitingCallback - If provided it will be called each time the sorting\n *  function is visiting the next element.\n */\n\nexport default class Sort {\n  constructor(originalCallbacks) {\n    this.callbacks = Sort.initSortingCallbacks(originalCallbacks);\n    this.comparator = new Comparator(this.callbacks.compareCallback);\n  }\n\n  /**\n   * @param {SorterCallbacks} originalCallbacks\n   * @returns {SorterCallbacks}\n   */\n  static initSortingCallbacks(originalCallbacks) {\n    const callbacks = originalCallbacks || {};\n    const stubCallback = () => {};\n\n    callbacks.compareCallback = callbacks.compareCallback || undefined;\n    callbacks.visitingCallback = callbacks.visitingCallback || stubCallback;\n\n    return callbacks;\n  }\n\n  sort() {\n    throw new Error('sort method must be implemented');\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/SortTester.js",
    "content": "export const sortedArr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];\nexport const reverseArr = [20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];\nexport const notSortedArr = [15, 8, 5, 12, 10, 1, 16, 9, 11, 7, 20, 3, 2, 6, 17, 18, 4, 13, 14, 19];\nexport const equalArr = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];\nexport const negativeArr = [-1, 0, 5, -10, 20, 13, -7, 3, 2, -3];\nexport const negativeArrSorted = [-10, -7, -3, -1, 0, 2, 3, 5, 13, 20];\n\nexport class SortTester {\n  static testSort(SortingClass) {\n    const sorter = new SortingClass();\n\n    expect(sorter.sort([])).toEqual([]);\n    expect(sorter.sort([1])).toEqual([1]);\n    expect(sorter.sort([1, 2])).toEqual([1, 2]);\n    expect(sorter.sort([2, 1])).toEqual([1, 2]);\n    expect(sorter.sort([3, 4, 2, 1, 0, 0, 4, 3, 4, 2])).toEqual([0, 0, 1, 2, 2, 3, 3, 4, 4, 4]);\n    expect(sorter.sort(sortedArr)).toEqual(sortedArr);\n    expect(sorter.sort(reverseArr)).toEqual(sortedArr);\n    expect(sorter.sort(notSortedArr)).toEqual(sortedArr);\n    expect(sorter.sort(equalArr)).toEqual(equalArr);\n  }\n\n  static testNegativeNumbersSort(SortingClass) {\n    const sorter = new SortingClass();\n    expect(sorter.sort(negativeArr)).toEqual(negativeArrSorted);\n  }\n\n  static testSortWithCustomComparator(SortingClass) {\n    const callbacks = {\n      compareCallback: (a, b) => {\n        if (a.length === b.length) {\n          return 0;\n        }\n        return a.length < b.length ? -1 : 1;\n      },\n    };\n\n    const sorter = new SortingClass(callbacks);\n\n    expect(sorter.sort([''])).toEqual(['']);\n    expect(sorter.sort(['a'])).toEqual(['a']);\n    expect(sorter.sort(['aa', 'a'])).toEqual(['a', 'aa']);\n    expect(sorter.sort(['aa', 'q', 'bbbb', 'ccc'])).toEqual(['q', 'aa', 'ccc', 'bbbb']);\n    expect(sorter.sort(['aa', 'aa'])).toEqual(['aa', 'aa']);\n  }\n\n  static testSortStability(SortingClass) {\n    const callbacks = {\n      compareCallback: (a, b) => {\n        if (a.length === b.length) {\n          return 0;\n        }\n        return a.length < b.length ? -1 : 1;\n      },\n    };\n\n    const sorter = new SortingClass(callbacks);\n\n    expect(sorter.sort(['bb', 'aa', 'c'])).toEqual(['c', 'bb', 'aa']);\n    expect(sorter.sort(['aa', 'q', 'a', 'bbbb', 'ccc'])).toEqual(['q', 'a', 'aa', 'ccc', 'bbbb']);\n  }\n\n  static testAlgorithmTimeComplexity(SortingClass, arrayToBeSorted, numberOfVisits) {\n    const visitingCallback = jest.fn();\n    const callbacks = { visitingCallback };\n    const sorter = new SortingClass(callbacks);\n\n    sorter.sort(arrayToBeSorted);\n\n    expect(visitingCallback).toHaveBeenCalledTimes(numberOfVisits);\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/__test__/Sort.test.js",
    "content": "import Sort from '../Sort';\n\ndescribe('Sort', () => {\n  it('should throw an error when trying to call Sort.sort() method directly', () => {\n    function doForbiddenSort() {\n      const sorter = new Sort();\n      sorter.sort();\n    }\n\n    expect(doForbiddenSort).toThrow();\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/bubble-sort/BubbleSort.js",
    "content": "import Sort from '../Sort';\n\nexport default class BubbleSort extends Sort {\n  sort(originalArray) {\n    // Flag that holds info about whether the swap has occur or not.\n    let swapped = false;\n    // Clone original array to prevent its modification.\n    const array = [...originalArray];\n\n    for (let i = 1; i < array.length; i += 1) {\n      swapped = false;\n\n      // Call visiting callback.\n      this.callbacks.visitingCallback(array[i]);\n\n      for (let j = 0; j < array.length - i; j += 1) {\n        // Call visiting callback.\n        this.callbacks.visitingCallback(array[j]);\n\n        // Swap elements if they are in wrong order.\n        if (this.comparator.lessThan(array[j + 1], array[j])) {\n          [array[j], array[j + 1]] = [array[j + 1], array[j]];\n\n          // Register the swap.\n          swapped = true;\n        }\n      }\n\n      // If there were no swaps then array is already sorted and there is\n      // no need to proceed.\n      if (!swapped) {\n        return array;\n      }\n    }\n\n    return array;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/bubble-sort/README.md",
    "content": "# Bubble Sort\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nBubble sort, sometimes referred to as sinking sort, is a\nsimple sorting algorithm that repeatedly steps through\nthe list to be sorted, compares each pair of adjacent\nitems and swaps them if they are in the wrong order\n(ascending or descending arrangement). The pass through\nthe list is repeated until no swaps are needed, which\nindicates that the list is sorted.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort)\n- [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/bubble-sort/README.pt-BR.md",
    "content": "# Bubble Sort\n\n_Leia isso em outros idiomas:_\n[_English_](README.md)\n\nO 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.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |           |\n\n## Referências\n\n- [Wikipedia](https://pt.wikipedia.org/wiki/Bubble_sort)\n- [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n"
  },
  {
    "path": "src/algorithms/sorting/bubble-sort/__test__/BubbleSort.test.js",
    "content": "import BubbleSort from '../BubbleSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 20;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 189;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 209;\nconst EQUAL_ARRAY_VISITING_COUNT = 20;\n\ndescribe('BubbleSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(BubbleSort);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(BubbleSort);\n  });\n\n  it('should do stable sorting', () => {\n    SortTester.testSortStability(BubbleSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(BubbleSort);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      BubbleSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      BubbleSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      BubbleSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      BubbleSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/bucket-sort/BucketSort.js",
    "content": "import RadixSort from '../radix-sort/RadixSort';\n\n/**\n * Bucket Sort\n *\n * @param {number[]} arr\n * @param {number} bucketsNum\n * @return {number[]}\n */\nexport default function BucketSort(arr, bucketsNum = 1) {\n  const buckets = new Array(bucketsNum).fill(null).map(() => []);\n\n  const minValue = Math.min(...arr);\n  const maxValue = Math.max(...arr);\n\n  const bucketSize = Math.ceil(Math.max(1, (maxValue - minValue) / bucketsNum));\n\n  // Place elements into buckets.\n  for (let i = 0; i < arr.length; i += 1) {\n    const currValue = arr[i];\n    const bucketIndex = Math.floor((currValue - minValue) / bucketSize);\n\n    // Edge case for max value.\n    if (bucketIndex === bucketsNum) {\n      buckets[bucketsNum - 1].push(currValue);\n    } else {\n      buckets[bucketIndex].push(currValue);\n    }\n  }\n\n  // Sort individual buckets.\n  for (let i = 0; i < buckets.length; i += 1) {\n    // Let's use the Radix Sorter here. This may give us\n    // the average O(n + k) time complexity to sort one bucket\n    // (where k is a number of digits in the longest number).\n    buckets[i] = new RadixSort().sort(buckets[i]);\n  }\n\n  // Merge sorted buckets into final output.\n  const sortedArr = [];\n  for (let i = 0; i < buckets.length; i += 1) {\n    sortedArr.push(...buckets[i]);\n  }\n\n  return sortedArr;\n}\n"
  },
  {
    "path": "src/algorithms/sorting/bucket-sort/README.md",
    "content": "# Bucket Sort\n\n**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.\n\n## Algorithm\n\nBucket sort works as follows:\n\n1. Set up an array of initially empty `buckets`.\n2. **Scatter:** Go over the original array, putting each object in its `bucket`.\n3. Sort each non-empty `bucket`.\n4. **Gather:** Visit the `buckets` in order and put all elements back into the original array.\n\nElements are distributed among bins:\n\n![Elements are distributed among bins](./images/bucket_sort_1.png)\n\nThen, elements are sorted within each bin:\n\n![Elements are sorted within each bin](./images/bucket_sort_2.png)\n\n\n## Complexity\n\nThe computational complexity depends on the algorithm used to sort each bucket, the number of buckets to use, and whether the input is uniformly distributed.\n\nThe **worst-case** time complexity of bucket sort is\n`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\n`O(n * log(n))`.\n\nOn **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.\n\n## References\n\n- [Bucket Sort on Wikipedia](https://en.wikipedia.org/wiki/Bucket_sort)\n"
  },
  {
    "path": "src/algorithms/sorting/bucket-sort/__test__/BucketSort.test.js",
    "content": "import BucketSort from '../BucketSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n} from '../../SortTester';\n\ndescribe('BucketSort', () => {\n  it('should sort the array of numbers with different buckets amounts', () => {\n    expect(BucketSort(notSortedArr, 4)).toEqual(sortedArr);\n    expect(BucketSort(equalArr, 4)).toEqual(equalArr);\n    expect(BucketSort(reverseArr, 4)).toEqual(sortedArr);\n    expect(BucketSort(sortedArr, 4)).toEqual(sortedArr);\n\n    expect(BucketSort(notSortedArr, 10)).toEqual(sortedArr);\n    expect(BucketSort(equalArr, 10)).toEqual(equalArr);\n    expect(BucketSort(reverseArr, 10)).toEqual(sortedArr);\n    expect(BucketSort(sortedArr, 10)).toEqual(sortedArr);\n\n    expect(BucketSort(notSortedArr, 50)).toEqual(sortedArr);\n    expect(BucketSort(equalArr, 50)).toEqual(equalArr);\n    expect(BucketSort(reverseArr, 50)).toEqual(sortedArr);\n    expect(BucketSort(sortedArr, 50)).toEqual(sortedArr);\n  });\n\n  it('should sort the array of numbers with the default buckets of 1', () => {\n    expect(BucketSort(notSortedArr)).toEqual(sortedArr);\n    expect(BucketSort(equalArr)).toEqual(equalArr);\n    expect(BucketSort(reverseArr)).toEqual(sortedArr);\n    expect(BucketSort(sortedArr)).toEqual(sortedArr);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/counting-sort/CountingSort.js",
    "content": "import Sort from '../Sort';\n\nexport default class CountingSort extends Sort {\n  /**\n   * @param {number[]} originalArray\n   * @param {number} [smallestElement]\n   * @param {number} [biggestElement]\n   */\n  sort(originalArray, smallestElement = undefined, biggestElement = undefined) {\n    // Init biggest and smallest elements in array in order to build number bucket array later.\n    let detectedSmallestElement = smallestElement || 0;\n    let detectedBiggestElement = biggestElement || 0;\n\n    if (smallestElement === undefined || biggestElement === undefined) {\n      originalArray.forEach((element) => {\n        // Visit element.\n        this.callbacks.visitingCallback(element);\n\n        // Detect biggest element.\n        if (this.comparator.greaterThan(element, detectedBiggestElement)) {\n          detectedBiggestElement = element;\n        }\n\n        // Detect smallest element.\n        if (this.comparator.lessThan(element, detectedSmallestElement)) {\n          detectedSmallestElement = element;\n        }\n      });\n    }\n\n    // Init buckets array.\n    // This array will hold frequency of each number from originalArray.\n    const buckets = Array(detectedBiggestElement - detectedSmallestElement + 1).fill(0);\n\n    originalArray.forEach((element) => {\n      // Visit element.\n      this.callbacks.visitingCallback(element);\n\n      buckets[element - detectedSmallestElement] += 1;\n    });\n\n    // Add previous frequencies to the current one for each number in bucket\n    // to detect how many numbers less then current one should be standing to\n    // the left of current one.\n    for (let bucketIndex = 1; bucketIndex < buckets.length; bucketIndex += 1) {\n      buckets[bucketIndex] += buckets[bucketIndex - 1];\n    }\n\n    // Now let's shift frequencies to the right so that they show correct numbers.\n    // I.e. if we won't shift right than the value of buckets[5] will display how many\n    // elements less than 5 should be placed to the left of 5 in sorted array\n    // INCLUDING 5th. After shifting though this number will not include 5th anymore.\n    buckets.pop();\n    buckets.unshift(0);\n\n    // Now let's assemble sorted array.\n    const sortedArray = Array(originalArray.length).fill(null);\n    for (let elementIndex = 0; elementIndex < originalArray.length; elementIndex += 1) {\n      // Get the element that we want to put into correct sorted position.\n      const element = originalArray[elementIndex];\n\n      // Visit element.\n      this.callbacks.visitingCallback(element);\n\n      // Get correct position of this element in sorted array.\n      const elementSortedPosition = buckets[element - detectedSmallestElement];\n\n      // Put element into correct position in sorted array.\n      sortedArray[elementSortedPosition] = element;\n\n      // Increase position of current element in the bucket for future correct placements.\n      buckets[element - detectedSmallestElement] += 1;\n    }\n\n    // Return sorted array.\n    return sortedArray;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/counting-sort/README.md",
    "content": "# Counting Sort\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nIn computer science, **counting sort** is an algorithm for sorting \na collection of objects according to keys that are small integers; \nthat is, it is an integer sorting algorithm. It operates by \ncounting the number of objects that have each distinct key value, \nand using arithmetic on those counts to determine the positions \nof each key value in the output sequence. Its running time is \nlinear in the number of items and the difference between the \nmaximum and minimum key values, so it is only suitable for direct \nuse in situations where the variation in keys is not significantly \ngreater than the number of items. However, it is often used as a \nsubroutine in another sorting algorithm, radix sort, that can \nhandle larger keys more efficiently.\n\nBecause counting sort uses key values as indexes into an array, \nit is not a comparison sort, and the `Ω(n log n)` lower bound for \ncomparison sorting does not apply to it. Bucket sort may be used \nfor many of the same tasks as counting sort, with a similar time \nanalysis; however, compared to counting sort, bucket sort requires \nlinked lists, dynamic arrays or a large amount of preallocated \nmemory to hold the sets of items within each bucket, whereas \ncounting sort instead stores a single number (the count of items) \nper bucket.\n\nCounting sorting works best when the range of numbers for each array\nelement is very small.\n\n## Algorithm\n\n**Step I**\n\nIn first step we calculate the count of all the elements of the \ninput array `A`. Then Store the result in the count array `C`.\nThe way we count is depicted below.\n\n![Counting Sort](https://3.bp.blogspot.com/-jJchly1BkTc/WLGqCFDdvCI/AAAAAAAAAHA/luljAlz2ptMndIZNH0KLTTuQMNsfzDeFQCLcB/s1600/CSortUpdatedStepI.gif)\n\n**Step II**\n\nIn second step we calculate how many elements exist in the input \narray `A` which are less than or equals for the given index. \n`Ci` = numbers of elements less than or equals to `i` in input array.\n\n![Counting Sort](https://1.bp.blogspot.com/-1vFu-VIRa9Y/WLHGuZkdF3I/AAAAAAAAAHs/8jKu2dbQee4ap9xlVcNsILrclqw0UxAVACLcB/s1600/Step-II.png)\n\n**Step III**\n\nIn this step we place the input array `A` element at sorted \nposition by taking help of constructed count array `C` ,i.e what \nwe constructed in step two. We used the result array `B` to store \nthe sorted elements. Here we handled the index of `B` start from\nzero.\n \n![Counting Sort](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - biggest number in array |\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Counting_sort)\n- [YouTube](https://www.youtube.com/watch?v=OKd534EWcdk&index=61&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [EfficientAlgorithms](https://efficientalgorithms.blogspot.com/2016/09/lenear-sorting-counting-sort.html)\n"
  },
  {
    "path": "src/algorithms/sorting/counting-sort/README.pt-br.md",
    "content": "# Counting Sort\n\n_Leia isso em outros idiomas:_\n[_English_](README.md)\n\nEm ciência da computação, **counting sort** é um algoritmo para ordenar\numa coleção de objetos de acordo com chaves que são pequenos inteiros;\nou seja, é um algoritmo de ordenação de inteiros. Ele opera por\ncontando o número de objetos que têm cada valor de chave distinto,\ne usando aritmética nessas contagens para determinar as posições\nde cada valor de chave na sequência de saída. Seu tempo de execução é\nlinear no número de itens e a diferença entre o\nvalores de chave máximo e mínimo, portanto, é adequado apenas para\nuso em situações em que a variação de tonalidades não é significativamente\nmaior que o número de itens. No entanto, muitas vezes é usado como\nsub-rotina em outro algoritmo de ordenação, radix sort, que pode\nlidar com chaves maiores de forma mais eficiente.\n\nComo a classificação por contagem usa valores-chave como índices em um vetor,\nnão é uma ordenação por comparação, e o limite inferior `Ω(n log n)` para\na ordenação por comparação não se aplica a ele. A classificação por bucket pode ser usada\npara muitas das mesmas tarefas que a ordenação por contagem, com um tempo semelhante\nanálise; no entanto, em comparação com a classificação por contagem, a classificação por bucket requer\nlistas vinculadas, arrays dinâmicos ou uma grande quantidade de pré-alocados\nmemória para armazenar os conjuntos de itens dentro de cada bucket, enquanto\nA classificação por contagem armazena um único número (a contagem de itens)\npor balde.\n\nA classificação por contagem funciona melhor quando o intervalo de números para cada\nelemento do vetor é muito pequeno.\n\n## Algoritmo\n\n**Passo I**\n\nNa primeira etapa, calculamos a contagem de todos os elementos do\nvetor de entrada 'A'. Em seguida, armazene o resultado no vetor de contagem `C`.\nA maneira como contamos é descrita abaixo.\n\n![Counting Sort](https://3.bp.blogspot.com/-jJchly1BkTc/WLGqCFDdvCI/AAAAAAAAAHA/luljAlz2ptMndIZNH0KLTTuQMNsfzDeFQCLcB/s1600/CSortUpdatedStepI.gif)\n\n**Passo II**\n\nNa segunda etapa, calculamos quantos elementos existem na entrada\ndo vetor `A` que são menores ou iguais para o índice fornecido.\n`Ci` = números de elementos menores ou iguais a `i` no vetor de entrada.\n\n![Counting Sort](https://1.bp.blogspot.com/-1vFu-VIRa9Y/WLHGuZkdF3I/AAAAAAAAAHs/8jKu2dbQee4ap9xlVcNsILrclqw0UxAVACLcB/s1600/Step-II.png)\n\n**Passo III**\n\nNesta etapa, colocamos o elemento `A` do vetor de entrada em classificado\nposição usando a ajuda do vetor de contagem construída `C`, ou seja, o que\nconstruímos no passo dois. Usamos o vetor de resultados `B` para armazenar\nos elementos ordenados. Aqui nós lidamos com o índice de `B` começando de\nzero.\n \n![Counting Sort](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Sim       | r - Maior número no vetor |\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Counting_sort)\n- [YouTube](https://www.youtube.com/watch?v=OKd534EWcdk&index=61&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [EfficientAlgorithms](https://efficientalgorithms.blogspot.com/2016/09/lenear-sorting-counting-sort.html)\n"
  },
  {
    "path": "src/algorithms/sorting/counting-sort/__test__/CountingSort.test.js",
    "content": "import CountingSort from '../CountingSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 60;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 60;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 60;\nconst EQUAL_ARRAY_VISITING_COUNT = 60;\n\ndescribe('CountingSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(CountingSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(CountingSort);\n  });\n\n  it('should allow to use specify max/min integer value in array to make sorting faster', () => {\n    const visitingCallback = jest.fn();\n    const sorter = new CountingSort({ visitingCallback });\n\n    // Detect biggest number in array in prior.\n    const biggestElement = Math.max(...notSortedArr);\n\n    // Detect smallest number in array in prior.\n    const smallestElement = Math.min(...notSortedArr);\n\n    const sortedArray = sorter.sort(notSortedArr, smallestElement, biggestElement);\n\n    expect(sortedArray).toEqual(sortedArr);\n    // Normally visitingCallback is being called 60 times but in this case\n    // it should be called only 40 times.\n    expect(visitingCallback).toHaveBeenCalledTimes(40);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      CountingSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      CountingSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      CountingSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      CountingSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/heap-sort/HeapSort.js",
    "content": "import Sort from '../Sort';\nimport MinHeap from '../../../data-structures/heap/MinHeap';\n\nexport default class HeapSort extends Sort {\n  sort(originalArray) {\n    const sortedArray = [];\n    const minHeap = new MinHeap(this.callbacks.compareCallback);\n\n    // Insert all array elements to the heap.\n    originalArray.forEach((element) => {\n      // Call visiting callback.\n      this.callbacks.visitingCallback(element);\n\n      minHeap.add(element);\n    });\n\n    // Now we have min heap with minimal element always on top.\n    // Let's poll that minimal element one by one and thus form the sorted array.\n    while (!minHeap.isEmpty()) {\n      const nextMinElement = minHeap.poll();\n\n      // Call visiting callback.\n      this.callbacks.visitingCallback(nextMinElement);\n\n      sortedArray.push(nextMinElement);\n    }\n\n    return sortedArray;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/heap-sort/README.md",
    "content": "# Heap Sort\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nHeapsort is a comparison-based sorting algorithm.\nHeapsort can be thought of as an improved selection\nsort: like that algorithm, it divides its input into\na sorted and an unsorted region, and it iteratively\nshrinks the unsorted region by extracting the largest\nelement and moving that to the sorted region. The \nimprovement consists of the use of a heap data structure\nrather than a linear-time search to find the maximum.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Heapsort)\n"
  },
  {
    "path": "src/algorithms/sorting/heap-sort/README.pt-BR.md",
    "content": "# Heap Sort\n\n_Leia isso em outros idiomas:_\n[_English_](README.md)\n\nHeapsort é 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.\n\n![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)\n\n![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Não        |           |\n\n## Referências\n\n[Wikipedia](https://en.wikipedia.org/wiki/Heapsort)\n"
  },
  {
    "path": "src/algorithms/sorting/heap-sort/__test__/HeapSort.test.js",
    "content": "import HeapSort from '../HeapSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\n// These numbers don't take into account up/dow heapifying of the heap.\n// Thus these numbers are higher in reality.\nconst SORTED_ARRAY_VISITING_COUNT = 40;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 40;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 40;\nconst EQUAL_ARRAY_VISITING_COUNT = 40;\n\ndescribe('HeapSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(HeapSort);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(HeapSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(HeapSort);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      HeapSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      HeapSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      HeapSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      HeapSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/insertion-sort/InsertionSort.js",
    "content": "import Sort from '../Sort';\n\nexport default class InsertionSort extends Sort {\n  sort(originalArray) {\n    const array = [...originalArray];\n\n    // Go through all array elements...\n    for (let i = 1; i < array.length; i += 1) {\n      let currentIndex = i;\n\n      // Call visiting callback.\n      this.callbacks.visitingCallback(array[i]);\n\n      // Check if previous element is greater than current element.\n      // If so, swap the two elements.\n      while (\n        array[currentIndex - 1] !== undefined\n        && this.comparator.lessThan(array[currentIndex], array[currentIndex - 1])\n      ) {\n        // Call visiting callback.\n        this.callbacks.visitingCallback(array[currentIndex - 1]);\n\n        // Swap the elements.\n        [\n          array[currentIndex - 1],\n          array[currentIndex],\n        ] = [\n          array[currentIndex],\n          array[currentIndex - 1],\n        ];\n\n        // Shift current index left.\n        currentIndex -= 1;\n      }\n    }\n\n    return array;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/insertion-sort/README.md",
    "content": "# Insertion Sort\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nInsertion sort is a simple sorting algorithm that builds \nthe final sorted array (or list) one item at a time. \nIt is much less efficient on large lists than more \nadvanced algorithms such as quicksort, heapsort, or merge \nsort.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif)\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort)\n"
  },
  {
    "path": "src/algorithms/sorting/insertion-sort/README.pt-BR.md",
    "content": "# Insertion Sort\n\n_Leia isso em outros idiomas:_\n[_English_](README.md)\n\nA ordenação por inserção é um algoritmo de ordenação simples que criaa matriz classificada final (ou lista) um item de cada vez.\nÉ muito menos eficiente em grandes listas do que mais algoritmos avançados, como quicksort, heapsort ou merge\nordenar.\n\n![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif)\n\n![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |           |\n\n## Referências\n\n[Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort)\n"
  },
  {
    "path": "src/algorithms/sorting/insertion-sort/__test__/InsertionSort.test.js",
    "content": "import InsertionSort from '../InsertionSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 19;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 100;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 209;\nconst EQUAL_ARRAY_VISITING_COUNT = 19;\n\ndescribe('InsertionSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(InsertionSort);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(InsertionSort);\n  });\n\n  it('should do stable sorting', () => {\n    SortTester.testSortStability(InsertionSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(InsertionSort);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      InsertionSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      InsertionSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      InsertionSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      InsertionSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/merge-sort/MergeSort.js",
    "content": "import Sort from '../Sort';\n\nexport default class MergeSort extends Sort {\n  sort(originalArray) {\n    // Call visiting callback.\n    this.callbacks.visitingCallback(null);\n\n    // If array is empty or consists of one element then return this array since it is sorted.\n    if (originalArray.length <= 1) {\n      return originalArray;\n    }\n\n    // Split array on two halves.\n    const middleIndex = Math.floor(originalArray.length / 2);\n    const leftArray = originalArray.slice(0, middleIndex);\n    const rightArray = originalArray.slice(middleIndex, originalArray.length);\n\n    // Sort two halves of split array\n    const leftSortedArray = this.sort(leftArray);\n    const rightSortedArray = this.sort(rightArray);\n\n    // Merge two sorted arrays into one.\n    return this.mergeSortedArrays(leftSortedArray, rightSortedArray);\n  }\n\n  mergeSortedArrays(leftArray, rightArray) {\n    const sortedArray = [];\n\n    // Use array pointers to exclude old elements after they have been added to the sorted array.\n    let leftIndex = 0;\n    let rightIndex = 0;\n\n    while (leftIndex < leftArray.length && rightIndex < rightArray.length) {\n      let minElement = null;\n\n      // Find the minimum element between the left and right array.\n      if (this.comparator.lessThanOrEqual(leftArray[leftIndex], rightArray[rightIndex])) {\n        minElement = leftArray[leftIndex];\n        // Increment index pointer to the right\n        leftIndex += 1;\n      } else {\n        minElement = rightArray[rightIndex];\n        // Increment index pointer to the right\n        rightIndex += 1;\n      }\n\n      // Add the minimum element to the sorted array.\n      sortedArray.push(minElement);\n\n      // Call visiting callback.\n      this.callbacks.visitingCallback(minElement);\n    }\n\n    // There will be elements remaining from either the left OR the right\n    // Concatenate the remaining elements into the sorted array\n    return sortedArray\n      .concat(leftArray.slice(leftIndex))\n      .concat(rightArray.slice(rightIndex));\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/merge-sort/README.ko-KR.md",
    "content": "# 병합 정렬\n\n컴퓨터과학에서, 병합 정렬(일반적으로 mergesort라고 쓰는)은 효율적이고, 범용적인, 비교 기반의 정렬 알고리즘입니다. 대부분의 구현들은 안정적인 정렬을 만들어내며, 이는 정렬된 산출물에서 동일한 요소들의 입력 순서가 유지된다는 것을 의미합니다. 병합 정렬은 1945년에 John von Neumann이 만든 분할 정복 알고리즘입니다.\n\n병합 정렬의 예시입니다. 우선 리스트를 가장 작은 단위로 나누고(한 개의 요소), 두 개의 인접한 리스트를 정렬하고 병합하기 위해 각 요소와 인접한 리스트를 비교합니다. 마지막으로 모든 요소들은 정렬되고 병합됩니다.\n\n![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)\n\n재귀적인 병합 정렬 알고리즘은 7개의 정수값을 가진 배열을 정렬하는데 사용됩니다. 다음은 합병 정렬을 모방하기 위해 사람이 취하는 단계입니다.(하향식)\n\n![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)\n\n## 복잡도\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |\n\n## 참조\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)\n- [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/merge-sort/README.md",
    "content": "# Merge Sort\n\n_Read this in other languages:_\n[_한국어_](README.ko-KR.md),\n[_Português_](README.pt-BR.md)\n\nIn computer science, merge sort (also commonly spelled\nmergesort) is an efficient, general-purpose,\ncomparison-based sorting algorithm. Most implementations\nproduce a stable sort, which means that the implementation\npreserves the input order of equal elements in the sorted\noutput. Mergesort is a divide and conquer algorithm that\nwas invented by John von Neumann in 1945.\n\nAn example of merge sort. First divide the list into\nthe smallest unit (1 element), then compare each\nelement with the adjacent list to sort and merge the\ntwo adjacent lists. Finally all the elements are sorted\nand merged.\n\n![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)\n\nA recursive merge sort algorithm used to sort an array of 7\ninteger values. These are the steps a human would take to\nemulate merge sort (top-down).\n\n![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)\n- [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/merge-sort/README.pt-BR.md",
    "content": "# Merge Sort\n\n_Leia isso em outros idiomas:_\n[_한국어_](README.ko-KR.md),\n[_English_](README.md)\n\nEm ciência da computação, merge sort (também comumente escrito\nmergesort) é uma ferramenta eficiente, de propósito geral,\nalgoritmo de ordenação baseado em comparação. A maioria das implementações\nproduzir uma classificação estável, o que significa que a implementação\npreserva a ordem de entrada de elementos iguais na ordenação\nresultado. Mergesort é um algoritmo de divisão e conquista que\nfoi inventado por John von Neumann em 1945.\n\nUm exemplo de classificação de mesclagem. Primeiro divida a lista em\na menor unidade (1 elemento), então compare cada\nelemento com a lista adjacente para classificar e mesclar o\nduas listas adjacentes. Finalmente todos os elementos são ordenados\ne mesclado.\n\n![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)\n\nUm algoritmo de classificação de mesclagem recursivo usado para classificar uma matriz de 7\nvalores inteiros. Estes são os passos que um ser humano daria para\nemular merge sort (top-down).\n\n![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Sim       |           |\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)\n- [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/merge-sort/__test__/MergeSort.test.js",
    "content": "import MergeSort from '../MergeSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 79;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 102;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 87;\nconst EQUAL_ARRAY_VISITING_COUNT = 79;\n\ndescribe('MergeSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(MergeSort);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(MergeSort);\n  });\n\n  it('should do stable sorting', () => {\n    SortTester.testSortStability(MergeSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(MergeSort);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      MergeSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      MergeSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      MergeSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      MergeSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/quick-sort/QuickSort.js",
    "content": "import Sort from '../Sort';\n\nexport default class QuickSort extends Sort {\n  /**\n   * @param {*[]} originalArray\n   * @return {*[]}\n   */\n  sort(originalArray) {\n    // Clone original array to prevent it from modification.\n    const array = [...originalArray];\n\n    // If array has less than or equal to one elements then it is already sorted.\n    if (array.length <= 1) {\n      return array;\n    }\n\n    // Init left and right arrays.\n    const leftArray = [];\n    const rightArray = [];\n\n    // Take the first element of array as a pivot.\n    const pivotElement = array.shift();\n    const centerArray = [pivotElement];\n\n    // Split all array elements between left, center and right arrays.\n    while (array.length) {\n      const currentElement = array.shift();\n\n      // Call visiting callback.\n      this.callbacks.visitingCallback(currentElement);\n\n      if (this.comparator.equal(currentElement, pivotElement)) {\n        centerArray.push(currentElement);\n      } else if (this.comparator.lessThan(currentElement, pivotElement)) {\n        leftArray.push(currentElement);\n      } else {\n        rightArray.push(currentElement);\n      }\n    }\n\n    // Sort left and right arrays.\n    const leftArraySorted = this.sort(leftArray);\n    const rightArraySorted = this.sort(rightArray);\n\n    // Let's now join sorted left array with center array and with sorted right array.\n    return leftArraySorted.concat(centerArray, rightArraySorted);\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/quick-sort/QuickSortInPlace.js",
    "content": "import Sort from '../Sort';\n\nexport default class QuickSortInPlace extends Sort {\n  /** Sorting in place avoids unnecessary use of additional memory, but modifies input array.\n   *\n   * This process is difficult to describe, but much clearer with a visualization:\n   * @see: https://www.hackerearth.com/practice/algorithms/sorting/quick-sort/visualize/\n   *\n   * @param {*[]} originalArray - Not sorted array.\n   * @param {number} inputLowIndex\n   * @param {number} inputHighIndex\n   * @param {boolean} recursiveCall\n   * @return {*[]} - Sorted array.\n   */\n  sort(\n    originalArray,\n    inputLowIndex = 0,\n    inputHighIndex = originalArray.length - 1,\n    recursiveCall = false,\n  ) {\n    // Copies array on initial call, and then sorts in place.\n    const array = recursiveCall ? originalArray : [...originalArray];\n\n    /**\n     * The partitionArray() operates on the subarray between lowIndex and highIndex, inclusive.\n     * It arbitrarily chooses the last element in the subarray as the pivot.\n     * Then, it partially sorts the subarray into elements than are less than the pivot,\n     * and elements that are greater than or equal to the pivot.\n     * Each time partitionArray() is executed, the pivot element is in its final sorted position.\n     *\n     * @param {number} lowIndex\n     * @param {number} highIndex\n     * @return {number}\n     */\n    const partitionArray = (lowIndex, highIndex) => {\n      /**\n       * Swaps two elements in array.\n       * @param {number} leftIndex\n       * @param {number} rightIndex\n       */\n      const swap = (leftIndex, rightIndex) => {\n        const temp = array[leftIndex];\n        array[leftIndex] = array[rightIndex];\n        array[rightIndex] = temp;\n      };\n\n      const pivot = array[highIndex];\n      // visitingCallback is used for time-complexity analysis.\n      this.callbacks.visitingCallback(pivot);\n\n      let partitionIndex = lowIndex;\n      for (let currentIndex = lowIndex; currentIndex < highIndex; currentIndex += 1) {\n        if (this.comparator.lessThan(array[currentIndex], pivot)) {\n          swap(partitionIndex, currentIndex);\n          partitionIndex += 1;\n        }\n      }\n\n      // The element at the partitionIndex is guaranteed to be greater than or equal to pivot.\n      // All elements to the left of partitionIndex are guaranteed to be less than pivot.\n      // Swapping the pivot with the partitionIndex therefore places the pivot in its\n      // final sorted position.\n      swap(partitionIndex, highIndex);\n\n      return partitionIndex;\n    };\n\n    // Base case is when low and high converge.\n    if (inputLowIndex < inputHighIndex) {\n      const partitionIndex = partitionArray(inputLowIndex, inputHighIndex);\n      const RECURSIVE_CALL = true;\n      this.sort(array, inputLowIndex, partitionIndex - 1, RECURSIVE_CALL);\n      this.sort(array, partitionIndex + 1, inputHighIndex, RECURSIVE_CALL);\n    }\n\n    return array;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/quick-sort/README.md",
    "content": "# Quicksort\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Português_](README.pt-BR.md)\n\nQuicksort is a divide and conquer algorithm.\nQuicksort first divides a large array into two smaller \nsub-arrays: the low elements and the high elements.\nQuicksort can then recursively sort the sub-arrays\n\nThe steps are:\n\n1. Pick an element, called a pivot, from the array.\n2. Partitioning: reorder the array so that all elements with \nvalues less than the pivot come before the pivot, while all \nelements with values greater than the pivot come after it \n(equal values can go either way). After this partitioning, \nthe pivot is in its final position. This is called the \npartition operation.\n3. Recursively apply the above steps to the sub-array of \nelements with smaller values and separately to the \nsub-array of elements with greater values.\n\nAnimated visualization of the quicksort algorithm.\nThe horizontal lines are pivot values.\n\n![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **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 |\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Quicksort)\n- [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/quick-sort/README.pt-BR.md",
    "content": "# Quicksort\n\n_Leia isso em outros idiomas:_\n[_简体中文_](README.zh-CN.md),\n[_English_](README.md)\n\nQuicksort é um algoritmo de dividir para conquistar.\nQuicksort primeiro divide uma grande matriz em duas menores\nsubmatrizes: os elementos baixos e os elementos altos.\nO Quicksort pode então classificar recursivamente as submatrizes.\n\nAs etapas são:\n\n1. Escolha um elemento, denominado pivô, na matriz.\n2. Particionamento: reordene a matriz para que todos os elementos com\nvalores menores que o pivô estejam antes do pivô, enquanto todos\nelementos com valores maiores do que o pivô vêm depois dele\n(valores iguais podem ser usados em qualquer direção). Após este particionamento,\no pivô está em sua posição final. Isso é chamado de\noperação de partição.\n3. Aplique recursivamente as etapas acima à submatriz de\nelementos com valores menores e separadamente para o\nsubmatriz de elementos com valores maiores.\n\nVisualização animada do algoritmo quicksort.\nAs linhas horizontais são valores dinâmicos. \n\n![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **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)) |\n\n## Referências\n\n- [Wikipedia](https://pt.wikipedia.org/wiki/Quicksort)\n- [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/quick-sort/README.zh-CN.md",
    "content": "# 快速排序\n\n快速排序是一种分而治之的算法。快速排序首先将一个大数组分成两个较小的子数组：比某个数小的元素和比某个数大的元素。然后快速排序可以递归地对子数组进行排序。\n\n步骤是：\n\n1. 从数组中选择一个元素，称为基点\n\n2. 分区：对数组重新排序，使所有值小于基点的元素都在它左边，而所有值大于基点的元素都在它右边（相等的值可以放在任何一边）。在此分区之后，基点处于其最终位置（左边和右边的中间位置）。这称为分区操作。\n\n3. 递归地将上述步骤应用于左边的数组和右边的数组。\n\n快速排序算法的动画可视化。水平线是基点值。\n\n![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)\n\n## 复杂度\n\n| Name           |     Best      |    Average    |     Worst     | Memory | Stable | Comments                                                      |\n| -------------- | :-----------: | :-----------: | :-----------: | :----: | :----: | :------------------------------------------------------------ |\n| **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 |\n\n## 引用\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Quicksort)\n\n- [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/quick-sort/__test__/QuickSort.test.js",
    "content": "import QuickSort from '../QuickSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 190;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 62;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 190;\nconst EQUAL_ARRAY_VISITING_COUNT = 19;\n\ndescribe('QuickSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(QuickSort);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(QuickSort);\n  });\n\n  it('should do stable sorting', () => {\n    SortTester.testSortStability(QuickSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(QuickSort);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/quick-sort/__test__/QuickSortInPlace.test.js",
    "content": "import QuickSortInPlace from '../QuickSortInPlace';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 19;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 12;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 19;\nconst EQUAL_ARRAY_VISITING_COUNT = 19;\n\ndescribe('QuickSortInPlace', () => {\n  it('should sort array', () => {\n    SortTester.testSort(QuickSortInPlace);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(QuickSortInPlace);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(QuickSortInPlace);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSortInPlace,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSortInPlace,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSortInPlace,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      QuickSortInPlace,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/radix-sort/README.md",
    "content": "# Radix Sort\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md),\n\nIn computer science, **radix sort** is a non-comparative integer sorting\nalgorithm that sorts data with integer keys by grouping keys by the individual\ndigits which share the same significant position and value. A positional notation\nis required, but because integers can represent strings of characters\n(e.g., names or dates) and specially formatted floating point numbers, radix\nsort is not limited to integers.\n\n*Where does the name come from?*\n\nIn mathematical numeral systems, the *radix* or base is the number of unique digits,\nincluding the digit zero, used to represent numbers in a positional numeral system.\nFor example, a binary system (using numbers 0 and 1) has a radix of 2 and a decimal\nsystem (using numbers 0 to 9) has a radix of 10.\n\n## Efficiency\n\nThe topic of the efficiency of radix sort compared to other sorting algorithms is\nsomewhat tricky and subject to quite a lot of misunderstandings. Whether radix\nsort is equally efficient, less efficient or more efficient than the best\ncomparison-based algorithms depends on the details of the assumptions made.\nRadix sort complexity is `O(wn)` for `n` keys which are integers of word size `w`.\nSometimes `w` is presented as a constant, which would make radix sort better\n(for sufficiently large `n`) than the best comparison-based sorting algorithms,\nwhich all perform `O(n log n)` comparisons to sort `n` keys. However, in\ngeneral `w` cannot be considered a constant: if all `n` keys are distinct,\nthen `w` has to be at least `log n` for a random-access machine to be able to\nstore them in memory, which gives at best a time complexity `O(n log n)`. That\nwould seem to make radix sort at most equally efficient as the best\ncomparison-based sorts (and worse if keys are much longer than `log n`).\n\n![Radix Sort](./images/radix-sort.png)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - length of longest key |\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort)\n- [YouTube](https://www.youtube.com/watch?v=XiuSW_mEn7g&index=62&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [ResearchGate](https://www.researchgate.net/figure/Simplistic-illustration-of-the-steps-performed-in-a-radix-sort-In-this-example-the_fig1_291086231)\n"
  },
  {
    "path": "src/algorithms/sorting/radix-sort/README.pt-BR.md",
    "content": "# Radix Sort\n\n_Leia isso em outros idiomas:_\n[_English_](README.md)\n\nEm ciência da computação, **radix sort** é uma classificação inteira não comparativa\nalgoritmo que classifica os dados com chaves inteiras agrupando as chaves pelo indivíduo\ndígitos que compartilham a mesma posição e valor significativos. Uma notação posicional\né necessário, mas porque os números inteiros podem representar cadeias de caracteres\n(por exemplo, nomes ou datas) e números de ponto flutuante especialmente formatados, base\nsort não está limitado a inteiros.\n\n*De onde vem o nome?*\n\nEm sistemas numéricos matemáticos, a *radix* ou base é o número de dígitos únicos,\nincluindo o dígito zero, usado para representar números em um sistema de numeração posicional.\nPor exemplo, um sistema binário (usando números 0 e 1) tem uma raiz de 2 e um decimal\nsistema (usando números de 0 a 9) tem uma raiz de 10.\n\n## Eficiência\n\nO tópico da eficiência do radix sort comparado a outros algoritmos de ordenação é\num pouco complicado e sujeito a muitos mal-entendidos. Se raiz\nsort é igualmente eficiente, menos eficiente ou mais eficiente do que o melhor\nalgoritmos baseados em comparação depende dos detalhes das suposições feitas.\nA complexidade de classificação de raiz é `O(wn)` para chaves `n` que são inteiros de tamanho de palavra `w`.\nÀs vezes, `w` é apresentado como uma constante, o que tornaria a classificação radix melhor\n(para `n` suficientemente grande) do que os melhores algoritmos de ordenação baseados em comparação,\nque todos realizam comparações `O(n log n)` para classificar chaves `n`. No entanto, em\ngeral `w` não pode ser considerado uma constante: se todas as chaves `n` forem distintas,\nentão `w` tem que ser pelo menos `log n` para que uma máquina de acesso aleatório seja capaz de\narmazená-los na memória, o que dá na melhor das hipóteses uma complexidade de tempo `O(n log n)`. Este\nparece tornar a ordenação radix no máximo tão eficiente quanto a melhor\nordenações baseadas em comparação (e pior se as chaves forem muito mais longas que `log n`).\n\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)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Sim       | k - comprimento da chave mais longa |\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort)\n- [YouTube](https://www.youtube.com/watch?v=XiuSW_mEn7g&index=62&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [ResearchGate](https://www.researchgate.net/figure/Simplistic-illustration-of-the-steps-performed-in-a-radix-sort-In-this-example-the_fig1_291086231)\n"
  },
  {
    "path": "src/algorithms/sorting/radix-sort/RadixSort.js",
    "content": "import Sort from '../Sort';\n\n// Using charCode (a = 97, b = 98, etc), we can map characters to buckets from 0 - 25\nconst BASE_CHAR_CODE = 97;\nconst NUMBER_OF_POSSIBLE_DIGITS = 10;\nconst ENGLISH_ALPHABET_LENGTH = 26;\n\nexport default class RadixSort extends Sort {\n  /**\n   * @param {*[]} originalArray\n   * @return {*[]}\n   */\n  sort(originalArray) {\n    // Assumes all elements of array are of the same type\n    const isArrayOfNumbers = this.isArrayOfNumbers(originalArray);\n\n    let sortedArray = [...originalArray];\n    const numPasses = this.determineNumPasses(sortedArray);\n\n    for (let currentIndex = 0; currentIndex < numPasses; currentIndex += 1) {\n      const buckets = isArrayOfNumbers\n        ? this.placeElementsInNumberBuckets(sortedArray, currentIndex)\n        : this.placeElementsInCharacterBuckets(sortedArray, currentIndex, numPasses);\n\n      // Flatten buckets into sortedArray, and repeat at next index\n      sortedArray = buckets.reduce((acc, val) => {\n        return [...acc, ...val];\n      }, []);\n    }\n\n    return sortedArray;\n  }\n\n  /**\n   * @param {*[]} array\n   * @param {number} index\n   * @return {*[]}\n   */\n  placeElementsInNumberBuckets(array, index) {\n    // See below. These are used to determine which digit to use for bucket allocation\n    const modded = 10 ** (index + 1);\n    const divided = 10 ** index;\n    const buckets = this.createBuckets(NUMBER_OF_POSSIBLE_DIGITS);\n\n    array.forEach((element) => {\n      this.callbacks.visitingCallback(element);\n      if (element < divided) {\n        buckets[0].push(element);\n      } else {\n        /**\n         * Say we have element of 1,052 and are currently on index 1 (starting from 0). This means\n         * we want to use '5' as the bucket. `modded` would be 10 ** (1 + 1), which\n         * is 100. So we take 1,052 % 100 (52) and divide it by 10 (5.2) and floor it (5).\n         */\n        const currentDigit = Math.floor((element % modded) / divided);\n        buckets[currentDigit].push(element);\n      }\n    });\n\n    return buckets;\n  }\n\n  /**\n   * @param {*[]} array\n   * @param {number} index\n   * @param {number} numPasses\n   * @return {*[]}\n   */\n  placeElementsInCharacterBuckets(array, index, numPasses) {\n    const buckets = this.createBuckets(ENGLISH_ALPHABET_LENGTH);\n\n    array.forEach((element) => {\n      this.callbacks.visitingCallback(element);\n      const currentBucket = this.getCharCodeOfElementAtIndex(element, index, numPasses);\n      buckets[currentBucket].push(element);\n    });\n\n    return buckets;\n  }\n\n  /**\n   * @param {string} element\n   * @param {number} index\n   * @param {number} numPasses\n   * @return {number}\n   */\n  getCharCodeOfElementAtIndex(element, index, numPasses) {\n    // Place element in last bucket if not ready to organize\n    if ((numPasses - index) > element.length) {\n      return ENGLISH_ALPHABET_LENGTH - 1;\n    }\n\n    /**\n     * If each character has been organized, use first character to determine bucket,\n     * otherwise iterate backwards through element\n     */\n    const charPos = index > element.length - 1 ? 0 : element.length - index - 1;\n\n    return element.toLowerCase().charCodeAt(charPos) - BASE_CHAR_CODE;\n  }\n\n  /**\n   * Number of passes is determined by the length of the longest element in the array.\n   * For integers, this log10(num), and for strings, this would be the length of the string.\n   */\n  determineNumPasses(array) {\n    return this.getLengthOfLongestElement(array);\n  }\n\n  /**\n   * @param {*[]} array\n   * @return {number}\n   */\n  getLengthOfLongestElement(array) {\n    if (this.isArrayOfNumbers(array)) {\n      return Math.floor(Math.log10(Math.max(...array))) + 1;\n    }\n\n    return array.reduce((acc, val) => {\n      return val.length > acc ? val.length : acc;\n    }, -Infinity);\n  }\n\n  /**\n   * @param {*[]} array\n   * @return {boolean}\n   */\n  isArrayOfNumbers(array) {\n    // Assumes all elements of array are of the same type\n    return this.isNumber(array[0]);\n  }\n\n  /**\n   * @param {number} numBuckets\n   * @return {*[]}\n   */\n  createBuckets(numBuckets) {\n    /**\n     * Mapping buckets to an array instead of filling them with\n     * an array prevents each bucket from containing a reference to the same array\n     */\n    return new Array(numBuckets).fill(null).map(() => []);\n  }\n\n  /**\n   * @param {*} element\n   * @return {boolean}\n   */\n  isNumber(element) {\n    return Number.isInteger(element);\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/radix-sort/__test__/RadixSort.test.js",
    "content": "import RadixSort from '../RadixSort';\nimport { SortTester } from '../../SortTester';\n\n// Complexity constants.\nconst ARRAY_OF_STRINGS_VISIT_COUNT = 24;\nconst ARRAY_OF_INTEGERS_VISIT_COUNT = 77;\ndescribe('RadixSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(RadixSort);\n  });\n\n  it('should visit array of strings n (number of strings) x m (length of longest element) times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      RadixSort,\n      ['zzz', 'bb', 'a', 'rr', 'rrb', 'rrba'],\n      ARRAY_OF_STRINGS_VISIT_COUNT,\n    );\n  });\n\n  it('should visit array of integers n (number of elements) x m (length of longest integer) times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      RadixSort,\n      [3, 1, 75, 32, 884, 523, 4343456, 232, 123, 656, 343],\n      ARRAY_OF_INTEGERS_VISIT_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/selection-sort/README.md",
    "content": "# Selection Sort\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md).\n\nSelection sort is a sorting algorithm, specifically an \nin-place comparison sort. It has O(n2) time complexity, \nmaking it inefficient on large lists, and generally \nperforms worse than the similar insertion sort. \nSelection sort is noted for its simplicity, and it has \nperformance advantages over more complicated algorithms \nin certain situations, particularly where auxiliary \nmemory is limited.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/b/b0/Selection_sort_animation.gif)\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/9/94/Selection-Sort-Animation.gif)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Selection_sort)\n"
  },
  {
    "path": "src/algorithms/sorting/selection-sort/README.pt-BR.md",
    "content": "# Selection Sort\n\n_Leia isso em outros idiomas:_\n[_English_](README.md).\n\nSelection 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.\n\n![Visualização do algoritmo](https://upload.wikimedia.org/wikipedia/commons/b/b0/Selection_sort_animation.gif)\n\n![Visualização do algoritmo](https://upload.wikimedia.org/wikipedia/commons/9/94/Selection-Sort-Animation.gif)\n\n## Complexidade\n\n| Nome                  | Melhor          | Médio               | Pior                | Memória   | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------:  | :----------: |\n| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Não        |              |\n\n## Referências\n\n[Wikipedia](https://en.wikipedia.org/wiki/Selection_sort)\n"
  },
  {
    "path": "src/algorithms/sorting/selection-sort/SelectionSort.js",
    "content": "import Sort from '../Sort';\n\nexport default class SelectionSort extends Sort {\n  sort(originalArray) {\n    // Clone original array to prevent its modification.\n    const array = [...originalArray];\n\n    for (let i = 0; i < array.length - 1; i += 1) {\n      let minIndex = i;\n\n      // Call visiting callback.\n      this.callbacks.visitingCallback(array[i]);\n\n      // Find minimum element in the rest of array.\n      for (let j = i + 1; j < array.length; j += 1) {\n        // Call visiting callback.\n        this.callbacks.visitingCallback(array[j]);\n\n        if (this.comparator.lessThan(array[j], array[minIndex])) {\n          minIndex = j;\n        }\n      }\n\n      // If new minimum element has been found then swap it with current i-th element.\n      if (minIndex !== i) {\n        [array[i], array[minIndex]] = [array[minIndex], array[i]];\n      }\n    }\n\n    return array;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/selection-sort/__test__/SelectionSort.test.js",
    "content": "import SelectionSort from '../SelectionSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 209;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 209;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 209;\nconst EQUAL_ARRAY_VISITING_COUNT = 209;\n\ndescribe('SelectionSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(SelectionSort);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(SelectionSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(SelectionSort);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      SelectionSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      SelectionSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      SelectionSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      SelectionSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/sorting/shell-sort/README.md",
    "content": "# Shellsort\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md).\n\nShellsort, also known as Shell sort or Shell's method, \nis an in-place comparison sort. It can be seen as either a \ngeneralization of sorting by exchange (bubble sort) or sorting \nby insertion (insertion sort). The method starts by sorting \npairs of elements far apart from each other, then progressively \nreducing the gap between elements to be compared. Starting \nwith far apart elements, it can move some out-of-place \nelements into position faster than a simple nearest neighbor \nexchange\n\n![Shellsort](https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif)\n\n## How Shell Sort Works\n\nFor our example and ease of understanding, we take the interval \nof `4`. Make a virtual sub-list of all values located at the \ninterval of 4 positions. Here these values are \n`{35, 14}`, `{33, 19}`, `{42, 27}` and `{10, 44}`\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_4.jpg)\n\nWe compare values in each sub-list and swap them (if necessary)\nin the original array. After this step, the new array should\nlook like this\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_1.jpg)\n\nThen, we take interval of 2 and this gap generates two sub-lists \n- `{14, 27, 35, 42}`, `{19, 10, 33, 44}`\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_2.jpg)\n\nWe compare and swap the values, if required, in the original array.\nAfter this step, the array should look like this\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)\n\n> UPD: On the picture below there is a typo and result array is supposed to be `[14, 10, 27, 19, 35, 33, 42, 44]`.\n\nFinally, we sort the rest of the array using interval of value 1. \nShell sort uses insertion sort to sort the array.\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg)\n\n## Complexity\n\n| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |\n\n## References\n\n- [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)\n- [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)\n- [YouTube by Rob Edwards](https://www.youtube.com/watch?v=ddeLSDsYVp8&index=79&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/shell-sort/README.pt-BR.md",
    "content": "# Shellsort\n\n_Leia isso em outros idiomas:_\n[_English_](README.md).\n\nShellsort, também conhecido como Shell sort ou método de Shell,\né uma classificação de comparação in-loco. Pode ser visto tanto como um\ngeneralização da ordenação por troca (bubble sort) ou ordenação\npor inserção (ordenação por inserção). O método começa classificando\npares de elementos distantes um do outro, então progressivamente\nreduzindo a distância entre os elementos a serem comparados. Iniciando\ncom elementos distantes, pode mover alguns fora do lugar\nelementos em posição mais rápido do que um simples vizinho mais próximo\nintercâmbio\n\n![Shellsort](https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif)\n\n## Como o Shellsort funciona?\n\nPara nosso exemplo e facilidade de compreensão, tomamos o intervalo\nde `4`. Faça uma sub-lista virtual de todos os valores localizados no\nintervalo de 4 posições. Aqui esses valores são\n`{35, 14}`, `{33, 19}`, `{42, 27}` e `{10, 44}`\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_4.jpg)\n\nComparamos valores em cada sublista e os trocamos (se necessário)\nna matriz original. Após esta etapa, o novo array deve\nparece com isso\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_1.jpg)\n\nEntão, pegamos o intervalo de 2 e essa lacuna gera duas sub-listas\n- `{14, 27, 35, 42}`, `{19, 10, 33, 44}`\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_2.jpg)\n\nComparamos e trocamos os valores, se necessário, no array original.\nApós esta etapa, a matriz deve ficar assim\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)\n\n> 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]`.\n\nFinalmente, ordenamos o resto do array usando o intervalo de valor 1.\nA classificação de shell usa a classificação por inserção para classificar a matriz.\n\n![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg)\n\n## Complexidade\n\n| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |\n| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |\n| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | Não         |           |\n\n## Referências\n\n- [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)\n- [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)\n- [YouTube by Rob Edwards](https://www.youtube.com/watch?v=ddeLSDsYVp8&index=79&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/sorting/shell-sort/ShellSort.js",
    "content": "import Sort from '../Sort';\n\nexport default class ShellSort extends Sort {\n  sort(originalArray) {\n    // Prevent original array from mutations.\n    const array = [...originalArray];\n\n    // Define a gap distance.\n    let gap = Math.floor(array.length / 2);\n\n    // Until gap is bigger then zero do elements comparisons and swaps.\n    while (gap > 0) {\n      // Go and compare all distant element pairs.\n      for (let i = 0; i < (array.length - gap); i += 1) {\n        let currentIndex = i;\n        let gapShiftedIndex = i + gap;\n\n        while (currentIndex >= 0) {\n          // Call visiting callback.\n          this.callbacks.visitingCallback(array[currentIndex]);\n\n          // Compare and swap array elements if needed.\n          if (this.comparator.lessThan(array[gapShiftedIndex], array[currentIndex])) {\n            const tmp = array[currentIndex];\n            array[currentIndex] = array[gapShiftedIndex];\n            array[gapShiftedIndex] = tmp;\n          }\n\n          gapShiftedIndex = currentIndex;\n          currentIndex -= gap;\n        }\n      }\n\n      // Shrink the gap.\n      gap = Math.floor(gap / 2);\n    }\n\n    // Return sorted copy of an original array.\n    return array;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/sorting/shell-sort/__test__/ShellSort.test.js",
    "content": "import ShellSort from '../ShellSort';\nimport {\n  equalArr,\n  notSortedArr,\n  reverseArr,\n  sortedArr,\n  SortTester,\n} from '../../SortTester';\n\n// Complexity constants.\nconst SORTED_ARRAY_VISITING_COUNT = 320;\nconst NOT_SORTED_ARRAY_VISITING_COUNT = 320;\nconst REVERSE_SORTED_ARRAY_VISITING_COUNT = 320;\nconst EQUAL_ARRAY_VISITING_COUNT = 320;\n\ndescribe('ShellSort', () => {\n  it('should sort array', () => {\n    SortTester.testSort(ShellSort);\n  });\n\n  it('should sort array with custom comparator', () => {\n    SortTester.testSortWithCustomComparator(ShellSort);\n  });\n\n  it('should sort negative numbers', () => {\n    SortTester.testNegativeNumbersSort(ShellSort);\n  });\n\n  it('should visit EQUAL array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      ShellSort,\n      equalArr,\n      EQUAL_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      ShellSort,\n      sortedArr,\n      SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit NOT SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      ShellSort,\n      notSortedArr,\n      NOT_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n\n  it('should visit REVERSE SORTED array element specified number of times', () => {\n    SortTester.testAlgorithmTimeComplexity(\n      ShellSort,\n      reverseArr,\n      REVERSE_SORTED_ARRAY_VISITING_COUNT,\n    );\n  });\n});\n"
  },
  {
    "path": "src/algorithms/stack/valid-parentheses/README.md",
    "content": "# Valid Parentheses Problem\n\nGiven a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.\n\nAn input string is valid if:\n\nOpen brackets must be closed by the same type of brackets.\nOpen brackets must be closed in the correct order.\nEvery close bracket has a corresponding open bracket of the same type.\n \n\nExample 1:\n\n`Input: s = \"()\"`\n\nOutput: true\n\nExample 2:\n\n`Input: s = \"()[]{}\"`\n\nOutput: true\n\nExample 3:\n\n`Input: s = \"(]\"`\n\nOutput: false\n\nThis is actually a very common interview question and a very good example of how to use a stack data structure to solve problems. \n\n## Solution\nThe problem can be solved in two ways\n\n### Bruteforce Approach\nWe can iterate through the string and then for each character in the string, we check for it's last closing character in the the string. Once we find the last closing character in the string, we remove both characters and then repeat the iteration, if we don't find a closing character for an opening character, then the string is invalid. The time complexity of this would be O(n^2) which is not so efficient.\n\n### Using a Stack\nWe can use a hashtable to store all opening characters and the value would be the respective closing character. We can then iterate through the string and if we encounter an opening parantheses, we push it's closing character to the stack. If we ecounter a closing paraentheses, then we pop the stack and confirm that the popped element is equal to the current closing parentheses character. If it is not then the string is invalid. At the end of the iteration, we also need to check that the stack is empty. If it is not then the string is invalid. If it is, then the string is valid. This is a more efficient approach with a Time complexity and Space complexity of O(n).\n\n\n## References\n\n- [Leetcode](https://leetcode.com/problems/valid-parentheses/)\n"
  },
  {
    "path": "src/algorithms/stack/valid-parentheses/__test__/validParentheses.test.js",
    "content": "import isValid from '../validParentheses';\n\ndescribe('validParentheses', () => {\n  it('should return false when string is empty', () => {\n    expect(isValid('')).toBe(false);\n  });\n\n  it('should return true when string contains valid parentheses in correct order', () => {\n    expect(isValid('()')).toBe(true);\n    expect(isValid('()[]{}')).toBe(true);\n    expect(isValid('((({[]})))')).toBe(true);\n  });\n\n  it('should return false when string contains invalid parentheses', () => {\n    expect(isValid('(]')).toBe(false);\n    expect(isValid('()[]{} }')).toBe(false);\n    expect(isValid('((({[(]})))')).toBe(false);\n  });\n\n  it('should return false when string contains valid parentheses in wrong order', () => {\n    expect(isValid('({)}')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/stack/valid-parentheses/validParentheses.js",
    "content": "import Stack from '../../../data-structures/stack/Stack';\nimport HashTable from '../../../data-structures/hash-table/HashTable';\n\n// Declare hashtable containg opening parentheses as key and it's closing parentheses as value.\nconst hashTable = new HashTable(3);\nhashTable.set('{', '}');\nhashTable.set('(', ')');\nhashTable.set('[', ']');\n\n/**\n * Check if string has valid parentheses.\n *\n * @param {string} parenthesesString\n * @return {boolean}\n */\nexport default function isValid(parenthesesString) {\n  // If string is empty return false\n  if (parenthesesString.length === 0) {\n    return false;\n  }\n  // Create stack\n  const stack = new Stack();\n\n  // Loop through each character of string\n  for (let i = 0; i < parenthesesString.length; i += 1) {\n    const currentCharacter = parenthesesString[i];\n    // If character is opening parentheses push it's closing parentheses to stack\n    if (hashTable.has(currentCharacter)) {\n      stack.push(hashTable.get(currentCharacter));\n    } else {\n      /* If character is a closing parentheses then,:\n      check If stack is empty, if it is return false.\n      if stack is not empty, pop from stack and compare it with current character.\n      If they are not same return false. */\n      if (stack.isEmpty() || stack.pop() !== currentCharacter) {\n        return false;\n      }\n    }\n  }\n  // If stack is empty return true else return false\n  return stack.isEmpty();\n}\n"
  },
  {
    "path": "src/algorithms/statistics/weighted-random/README.md",
    "content": "# Weighted Random\n\n![Weighted Random](images/cover.png)\n\n## What is \"Weighted Random\"\n\nLet'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: `[ '🍌', '🍎', '🥕' ]`.\n\nThe 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:\n\n- you would like to eat `🍎 apples` more often (`7` out of `3 + 7 + 1 = 11` times),\n- then you would like to eat `bananas 🍌` less often (only `3` out of `11` times),\n- and the `carrots 🥕` you really don't like (want to eat it only `1` out of `11` times).\n\n> 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]`).\n\nThe **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\nExample of the function interface:\n\n```javascript\nconst items =   [ '🍌', '🍎', '🥕' ];\nconst weights = [  3,    7,    1  ];\n\nfunction weightedRandom(items, weights) {\n  // implementation goes here ...\n}\n\nconst nextSnackToEat = weightedRandom(items, weights); // Could be '🍎'\n```\n\n## Applications of Weighted Random\n\n- 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.\n- 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.\n- 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.\n- And more...\n\n## The Algorithm\n\nThe **straightforward approach** would be to:\n\n1. Repeat each item in the list according to its weight.\n2. Pick the random item from the list.\n\nFor example in our case with fruits and vegetables we could generate the following list of size `3 + 7 + 1 = 11`:\n\n```javascript\nconst items =   [ '🍌', '🍎', '🥕' ];\nconst weights = [  3,    7,    1  ];\n\n// Repeating the items based on weights.\nconst weightedItems = [\n  '🍌', '🍌', '🍌',\n  '🍎', '🍎', '🍎', '🍎', '🍎', '🍎', '🍎',\n  '🥕',\n];\n\n// And now just pick the random item from weightedItems array.\n```\n\nHowever, 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.\n\nThe **more efficient approach** would be to:\n\n1. 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]`\n2. 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`.\n3. 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.\n\nThe 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\".\n\n```javascript\nconst weights =           [3, 7,  1 ];\nconst cumulativeWeights = [3, 10, 11];\n\n// In a pseudo-representation we may think about the cumulativeWeights array like this.\nconst pseudoCumulativeWeights = [\n  1, 2, 3,               // <-- [3] numbers\n  4, 5, 6, 7, 8, 9, 10,  // <-- [7] numbers\n  11,                    // <-- [1] number\n];\n```\n\nHere is an example of how the `weightedRandom` function might be implemented:\n\n```javascript\n/**\n * Picks the random item based on its weight.\n * The items with higher weight will be picked more often (with a higher probability).\n *\n * For example:\n * - items = ['banana', 'orange', 'apple']\n * - weights = [0, 0.2, 0.8]\n * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return\n * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)\n *\n * @param {any[]} items\n * @param {number[]} weights\n * @returns {{item: any, index: number}}\n */\nexport default function weightedRandom(items, weights) {\n  if (items.length !== weights.length) {\n    throw new Error('Items and weights must be of the same size');\n  }\n\n  if (!items.length) {\n    throw new Error('Items must not be empty');\n  }\n\n  // Preparing the cumulative weights array.\n  // For example:\n  // - weights = [1, 4, 3]\n  // - cumulativeWeights = [1, 5, 8]\n  const cumulativeWeights = [];\n  for (let i = 0; i < weights.length; i += 1) {\n    cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0);\n  }\n\n  // Getting the random number in a range of [0...sum(weights)]\n  // For example:\n  // - weights = [1, 4, 3]\n  // - maxCumulativeWeight = 8\n  // - range for the random number is [0...8]\n  const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1];\n  const randomNumber = maxCumulativeWeight * Math.random();\n\n  // Picking the random item based on its weight.\n  // The items with higher weight will be picked more often.\n  for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {\n    if (cumulativeWeights[itemIndex] >= randomNumber) {\n      return {\n        item: items[itemIndex],\n        index: itemIndex,\n      };\n    }\n  }\n}\n```\n\n## Implementation\n\n- Check the [weightedRandom.js](weightedRandom.js) file for the implementation of the `weightedRandom()` function.\n- Check the [weightedRandom.test.js](__test__/weightedRandom.test.js) file for the tests-cases.\n"
  },
  {
    "path": "src/algorithms/statistics/weighted-random/__test__/weightedRandom.test.js",
    "content": "import weightedRandom from '../weightedRandom';\n\ndescribe('weightedRandom', () => {\n  it('should throw an error when the number of weights does not match the number of items', () => {\n    const getWeightedRandomWithInvalidInputs = () => {\n      weightedRandom(['a', 'b', 'c'], [10, 0]);\n    };\n    expect(getWeightedRandomWithInvalidInputs).toThrow('Items and weights must be of the same size');\n  });\n\n  it('should throw an error when the number of weights or items are empty', () => {\n    const getWeightedRandomWithInvalidInputs = () => {\n      weightedRandom([], []);\n    };\n    expect(getWeightedRandomWithInvalidInputs).toThrow('Items must not be empty');\n  });\n\n  it('should correctly do random selection based on wights in straightforward cases', () => {\n    expect(weightedRandom(['a', 'b', 'c'], [1, 0, 0])).toEqual({ index: 0, item: 'a' });\n    expect(weightedRandom(['a', 'b', 'c'], [0, 1, 0])).toEqual({ index: 1, item: 'b' });\n    expect(weightedRandom(['a', 'b', 'c'], [0, 0, 1])).toEqual({ index: 2, item: 'c' });\n    expect(weightedRandom(['a', 'b', 'c'], [0, 1, 1])).not.toEqual({ index: 0, item: 'a' });\n    expect(weightedRandom(['a', 'b', 'c'], [1, 0, 1])).not.toEqual({ index: 1, item: 'b' });\n    expect(weightedRandom(['a', 'b', 'c'], [1, 1, 0])).not.toEqual({ index: 2, item: 'c' });\n  });\n\n  it('should correctly do random selection based on wights', () => {\n    // Number of times we're going to select the random items based on their weights.\n    const ATTEMPTS_NUM = 1000;\n    // The +/- delta in the number of times each item has been actually selected.\n    // I.e. if we want the item 'a' to be selected 300 times out of 1000 cases (30%)\n    // then 267 times is acceptable since it is bigger that 250 (which is 300 - 50)\n    // ans smaller than 350 (which is 300 + 50)\n    const THRESHOLD = 50;\n\n    const items = ['a', 'b', 'c']; // The actual items values don't matter.\n    const weights = [0.1, 0.3, 0.6];\n\n    const counter = [];\n    for (let i = 0; i < ATTEMPTS_NUM; i += 1) {\n      const randomItem = weightedRandom(items, weights);\n      if (!counter[randomItem.index]) {\n        counter[randomItem.index] = 1;\n      } else {\n        counter[randomItem.index] += 1;\n      }\n    }\n\n    for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {\n      /*\n        i.e. item with the index of 0 must be selected 100 times (ideally)\n        or with the threshold of [100 - 50, 100 + 50] times.\n\n        i.e. item with the index of 1 must be selected 300 times (ideally)\n        or with the threshold of [300 - 50, 300 + 50] times.\n\n        i.e. item with the index of 2 must be selected 600 times (ideally)\n        or with the threshold of [600 - 50, 600 + 50] times.\n       */\n      expect(counter[itemIndex]).toBeGreaterThan(ATTEMPTS_NUM * weights[itemIndex] - THRESHOLD);\n      expect(counter[itemIndex]).toBeLessThan(ATTEMPTS_NUM * weights[itemIndex] + THRESHOLD);\n    }\n  });\n});\n"
  },
  {
    "path": "src/algorithms/statistics/weighted-random/weightedRandom.js",
    "content": "/**\n * Picks the random item based on its weight.\n * The items with higher weight will be picked more often (with a higher probability).\n *\n * For example:\n * - items = ['banana', 'orange', 'apple']\n * - weights = [0, 0.2, 0.8]\n * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return\n * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)\n *\n * @param {any[]} items\n * @param {number[]} weights\n * @returns {{item: any, index: number}}\n */\n/* eslint-disable consistent-return */\nexport default function weightedRandom(items, weights) {\n  if (items.length !== weights.length) {\n    throw new Error('Items and weights must be of the same size');\n  }\n\n  if (!items.length) {\n    throw new Error('Items must not be empty');\n  }\n\n  // Preparing the cumulative weights array.\n  // For example:\n  // - weights = [1, 4, 3]\n  // - cumulativeWeights = [1, 5, 8]\n  const cumulativeWeights = [];\n  for (let i = 0; i < weights.length; i += 1) {\n    cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0);\n  }\n\n  // Getting the random number in a range of [0...sum(weights)]\n  // For example:\n  // - weights = [1, 4, 3]\n  // - maxCumulativeWeight = 8\n  // - range for the random number is [0...8]\n  const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1];\n  const randomNumber = maxCumulativeWeight * Math.random();\n\n  // Picking the random item based on its weight.\n  // The items with higher weight will be picked more often.\n  for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {\n    if (cumulativeWeights[itemIndex] >= randomNumber) {\n      return {\n        item: items[itemIndex],\n        index: itemIndex,\n      };\n    }\n  }\n}\n"
  },
  {
    "path": "src/algorithms/string/hamming-distance/README.md",
    "content": "# Hamming Distance\n\nthe Hamming distance between two strings of equal length is the \nnumber of positions at which the corresponding symbols are \ndifferent. In other words, it measures the minimum number of\nsubstitutions required to change one string into the other, or \nthe minimum number of errors that could have transformed one \nstring into the other. In a more general context, the Hamming \ndistance is one of several string metrics for measuring the \nedit distance between two sequences.\n\n## Examples\n\nThe Hamming distance between:\n\n- \"ka**rol**in\" and \"ka**thr**in\" is **3**.\n- \"k**a**r**ol**in\" and \"k**e**r**st**in\" is **3**.\n- 10**1**1**1**01 and 10**0**1**0**01 is **2**.\n- 2**17**3**8**96 and 2**23**3**7**96 is **3**.\n\n## References\n\n[Wikipedia](https://en.wikipedia.org/wiki/Hamming_distance)\n"
  },
  {
    "path": "src/algorithms/string/hamming-distance/__test__/hammingDistance.test.js",
    "content": "import hammingDistance from '../hammingDistance';\n\ndescribe('hammingDistance', () => {\n  it('should throw an error when trying to compare the strings of different lengths', () => {\n    const compareStringsOfDifferentLength = () => {\n      hammingDistance('a', 'aa');\n    };\n\n    expect(compareStringsOfDifferentLength).toThrow();\n  });\n\n  it('should calculate difference between two strings', () => {\n    expect(hammingDistance('a', 'a')).toBe(0);\n    expect(hammingDistance('a', 'b')).toBe(1);\n    expect(hammingDistance('abc', 'add')).toBe(2);\n    expect(hammingDistance('karolin', 'kathrin')).toBe(3);\n    expect(hammingDistance('karolin', 'kerstin')).toBe(3);\n    expect(hammingDistance('1011101', '1001001')).toBe(2);\n    expect(hammingDistance('2173896', '2233796')).toBe(3);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/hamming-distance/hammingDistance.js",
    "content": "/**\n * @param {string} a\n * @param {string} b\n * @return {number}\n */\nexport default function hammingDistance(a, b) {\n  if (a.length !== b.length) {\n    throw new Error('Strings must be of the same length');\n  }\n\n  let distance = 0;\n\n  for (let i = 0; i < a.length; i += 1) {\n    if (a[i] !== b[i]) {\n      distance += 1;\n    }\n  }\n\n  return distance;\n}\n"
  },
  {
    "path": "src/algorithms/string/knuth-morris-pratt/README.md",
    "content": "# Knuth–Morris–Pratt Algorithm\n\nThe Knuth–Morris–Pratt string searching algorithm (or \nKMP algorithm) searches for occurrences of a \"word\" `W` \nwithin a main \"text string\" `T` by employing the \nobservation that when a mismatch occurs, the word itself \nembodies sufficient information to determine where the \nnext match could begin, thus bypassing re-examination \nof previously matched characters.\n\n## Complexity\n\n- **Time:** `O(|W| + |T|)` (much faster comparing to trivial `O(|W| * |T|)`)\n- **Space:** `O(|W|)`\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm)\n- [YouTube](https://www.youtube.com/watch?v=GTJr8OvyEVQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/string/knuth-morris-pratt/__test__/knuthMorrisPratt.test.js",
    "content": "import knuthMorrisPratt from '../knuthMorrisPratt';\n\ndescribe('knuthMorrisPratt', () => {\n  it('should find word position in given text', () => {\n    expect(knuthMorrisPratt('', '')).toBe(0);\n    expect(knuthMorrisPratt('a', '')).toBe(0);\n    expect(knuthMorrisPratt('a', 'a')).toBe(0);\n    expect(knuthMorrisPratt('abcbcglx', 'abca')).toBe(-1);\n    expect(knuthMorrisPratt('abcbcglx', 'bcgl')).toBe(3);\n    expect(knuthMorrisPratt('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toBe(15);\n    expect(knuthMorrisPratt('abcxabcdabxabcdabcdabcy', 'abcdabca')).toBe(-1);\n    expect(knuthMorrisPratt('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toBe(12);\n    expect(knuthMorrisPratt('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toBe(11);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/knuth-morris-pratt/knuthMorrisPratt.js",
    "content": "/**\n * @see https://www.youtube.com/watch?v=GTJr8OvyEVQ\n * @param {string} word\n * @return {number[]}\n */\nfunction buildPatternTable(word) {\n  const patternTable = [0];\n  let prefixIndex = 0;\n  let suffixIndex = 1;\n\n  while (suffixIndex < word.length) {\n    if (word[prefixIndex] === word[suffixIndex]) {\n      patternTable[suffixIndex] = prefixIndex + 1;\n      suffixIndex += 1;\n      prefixIndex += 1;\n    } else if (prefixIndex === 0) {\n      patternTable[suffixIndex] = 0;\n      suffixIndex += 1;\n    } else {\n      prefixIndex = patternTable[prefixIndex - 1];\n    }\n  }\n\n  return patternTable;\n}\n\n/**\n * @param {string} text\n * @param {string} word\n * @return {number}\n */\nexport default function knuthMorrisPratt(text, word) {\n  if (word.length === 0) {\n    return 0;\n  }\n\n  let textIndex = 0;\n  let wordIndex = 0;\n\n  const patternTable = buildPatternTable(word);\n\n  while (textIndex < text.length) {\n    if (text[textIndex] === word[wordIndex]) {\n      // We've found a match.\n      if (wordIndex === word.length - 1) {\n        return (textIndex - word.length) + 1;\n      }\n      wordIndex += 1;\n      textIndex += 1;\n    } else if (wordIndex > 0) {\n      wordIndex = patternTable[wordIndex - 1];\n    } else {\n      // wordIndex = 0;\n      textIndex += 1;\n    }\n  }\n\n  return -1;\n}\n"
  },
  {
    "path": "src/algorithms/string/levenshtein-distance/README.md",
    "content": "# Levenshtein Distance\n\nThe Levenshtein distance is a string metric for measuring the \ndifference between two sequences. Informally, the Levenshtein \ndistance between two words is the minimum number of \nsingle-character edits (insertions, deletions or substitutions) \nrequired to change one word into the other.\n\n## Definition\n\nMathematically, the Levenshtein distance between two strings\n`a` and `b` (of length `|a|` and `|b|` respectively) is given by\n![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/4cf357d8f2135035207088d2c7b890fb4b64e410)\nwhere\n\n![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/f0a48ecfc9852c042382fdc33c19e11a16948e85)\n\nwhere \n![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/52512ede08444b13838c570ba4a3fc71d54dbce9)\nis the indicator function equal to `0` when\n![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/231fda9ee578f0328c5ca28088d01928bb0aaaec)\nand equal to 1 otherwise, and\n![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/bdc0315678caad28648aafedb6ebafb16bd1655c)\nis the distance between the first `i` characters of `a` and the first \n`j` characters of `b`.\n\nNote that the first element in the minimum corresponds to \ndeletion (from `a` to `b`), the second to insertion and \nthe third to match or mismatch, depending on whether the \nrespective symbols are the same.\n\n## Example\n\nFor example, the Levenshtein distance between `kitten` and \n`sitting` is `3`, since the following three edits change one \ninto the other, and there is no way to do it with fewer than \nthree edits:\n\n1. **k**itten → **s**itten (substitution of \"s\" for \"k\")\n2. sitt**e**n → sitt**i**n (substitution of \"i\" for \"e\")\n3. sittin → sittin**g** (insertion of \"g\" at the end).\n\n## Applications\n\nThis has a wide range of applications, for instance, spell checkers, correction \nsystems for optical character recognition, fuzzy string searching, and software \nto assist natural language translation based on translation memory.\n\n## Dynamic Programming Approach Explanation\n\nLet’s take a simple example of finding minimum edit distance between \nstrings `ME` and `MY`. Intuitively you already know that minimum edit distance \nhere is `1` operation, which is replacing `E` with `Y`. But \nlet’s try to formalize it in a form of the algorithm in order to be able to \ndo more complex examples like transforming `Saturday` into `Sunday`.\n\nTo apply the mathematical formula mentioned above to `ME → MY` transformation \nwe need to know minimum edit distances of `ME → M`, `M → MY` and `M → M` transformations\nin prior. Then we will need to pick the minimum one and add _one_ operation to \ntransform last letters `E → Y`. So minimum edit distance of `ME → MY` transformation \nis being calculated based on three previously possible transformations.\n\nTo explain this further let’s draw the following matrix:\n\n![Levenshtein Matrix](https://cdn-images-1.medium.com/max/1600/1*aTunSUoy0BJyYBVn4tWGrA.png)\n\n- Cell `(0:1)` contains red number 1. It means that we need 1 operation to \ntransform `M` to an empty string. And it is by deleting `M`. This is why this number is red.\n- Cell `(0:2)` contains red number 2. It means that we need 2 operations \nto transform `ME` to an empty string. And it is by deleting `E` and `M`.\n- Cell `(1:0)` contains green number 1. It means that we need 1 operation \nto transform an empty string to `M`. And it is by inserting `M`. This is why this number is green.\n- Cell `(2:0)` contains green number 2. It means that we need 2 operations \nto transform an empty string to `MY`. And it is by inserting `Y` and  `M`.\n- Cell `(1:1)` contains number 0. It means that it costs nothing \nto transform `M` into `M`.\n- Cell `(1:2)` contains red number 1. It means that we need 1 operation \nto transform `ME` to `M`. And it is by deleting `E`.\n- And so on...\n\nThis looks easy for such small matrix as ours (it is only `3x3`). But here you\nmay find basic concepts that may be applied to calculate all those numbers for\nbigger matrices (let’s say a `9x7` matrix for `Saturday → Sunday` transformation).\n\nAccording to the formula you only need three adjacent cells `(i-1:j)`, `(i-1:j-1)`, and `(i:j-1)` to\ncalculate the number for current cell `(i:j)`. All we need to do is to find the \nminimum of those three cells and then add `1` in case if we have different \nletters in `i`'s row and `j`'s column.\n\nYou may clearly see the recursive nature of the problem.\n\n![Levenshtein Matrix](https://cdn-images-1.medium.com/max/1600/1*w8UB4DSvBnAK6mBXRGQDjw.png)\n\nLet's draw a decision graph for this problem.\n\n![Minimum Edit Distance Decision Graph](https://cdn-images-1.medium.com/max/1600/1*8jD0qvr5B9PwRFM_9z7q9A.png)\n\nYou may see a number of overlapping sub-problems on the picture that are marked \nwith red. Also there is no way to reduce the number of operations and make it \nless than a minimum of those three adjacent cells from the formula. \n\nAlso you may notice that each cell number in the matrix is being calculated \nbased on previous ones. Thus the tabulation technique (filling the cache in \nbottom-up direction) is being applied here.\n\nApplying this principle further we may solve more complicated cases like \nwith `Saturday → Sunday` transformation.\n\n![Levenshtein distance](https://cdn-images-1.medium.com/max/2600/1*497gMaFErzJpCXG7kS_7dw.png)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Levenshtein_distance)\n- [YouTube](https://www.youtube.com/watch?v=We3YDTzNXEk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [ITNext](https://itnext.io/dynamic-programming-vs-divide-and-conquer-2fea680becbe)\n"
  },
  {
    "path": "src/algorithms/string/levenshtein-distance/__test__/levenshteinDistance.test.js",
    "content": "import levenshteinDistance from '../levenshteinDistance';\n\ndescribe('levenshteinDistance', () => {\n  it('should calculate edit distance between two strings', () => {\n    expect(levenshteinDistance('', '')).toBe(0);\n    expect(levenshteinDistance('a', '')).toBe(1);\n    expect(levenshteinDistance('', 'a')).toBe(1);\n    expect(levenshteinDistance('abc', '')).toBe(3);\n    expect(levenshteinDistance('', 'abc')).toBe(3);\n\n    // Should just add I to the beginning.\n    expect(levenshteinDistance('islander', 'slander')).toBe(1);\n\n    // Needs to substitute M by K, T by M and add an A to the end\n    expect(levenshteinDistance('mart', 'karma')).toBe(3);\n\n    // Substitute K by S, E by I and insert G at the end.\n    expect(levenshteinDistance('kitten', 'sitting')).toBe(3);\n\n    // Should add 4 letters FOOT at the beginning.\n    expect(levenshteinDistance('ball', 'football')).toBe(4);\n\n    // Should delete 4 letters FOOT at the beginning.\n    expect(levenshteinDistance('football', 'foot')).toBe(4);\n\n    // Needs to substitute the first 5 chars: INTEN by EXECU\n    expect(levenshteinDistance('intention', 'execution')).toBe(5);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/levenshtein-distance/levenshteinDistance.js",
    "content": "/**\n * @param {string} a\n * @param {string} b\n * @return {number}\n */\nexport default function levenshteinDistance(a, b) {\n  // Create empty edit distance matrix for all possible modifications of\n  // substrings of a to substrings of b.\n  const distanceMatrix = Array(b.length + 1).fill(null).map(() => Array(a.length + 1).fill(null));\n\n  // Fill the first row of the matrix.\n  // If this is first row then we're transforming empty string to a.\n  // In this case the number of transformations equals to size of a substring.\n  for (let i = 0; i <= a.length; i += 1) {\n    distanceMatrix[0][i] = i;\n  }\n\n  // Fill the first column of the matrix.\n  // If this is first column then we're transforming empty string to b.\n  // In this case the number of transformations equals to size of b substring.\n  for (let j = 0; j <= b.length; j += 1) {\n    distanceMatrix[j][0] = j;\n  }\n\n  for (let j = 1; j <= b.length; j += 1) {\n    for (let i = 1; i <= a.length; i += 1) {\n      const indicator = a[i - 1] === b[j - 1] ? 0 : 1;\n      distanceMatrix[j][i] = Math.min(\n        distanceMatrix[j][i - 1] + 1, // deletion\n        distanceMatrix[j - 1][i] + 1, // insertion\n        distanceMatrix[j - 1][i - 1] + indicator, // substitution\n      );\n    }\n  }\n\n  return distanceMatrix[b.length][a.length];\n}\n"
  },
  {
    "path": "src/algorithms/string/longest-common-substring/README.md",
    "content": "# Longest Common Substring Problem\n\nThe longest common substring problem is to find the longest string \n(or strings) that is a substring (or are substrings) of two or more \nstrings.\n\n## Example\n\nThe longest common substring of the strings `ABABC`, `BABCA` and \n`ABCBA` is string `ABC` of length 3. Other common substrings are\n`A`, `AB`, `B`, `BA`, `BC` and `C`.\n\n```\nABABC\n  |||\n BABCA\n  |||\n  ABCBA\n```\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_substring_problem)\n- [YouTube](https://www.youtube.com/watch?v=BysNXJHzCEs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/string/longest-common-substring/__test__/longestCommonSubstring.test.js",
    "content": "import longestCommonSubstring from '../longestCommonSubstring';\n\ndescribe('longestCommonSubstring', () => {\n  it('should find longest common substring between two strings', () => {\n    expect(longestCommonSubstring('', '')).toBe('');\n    expect(longestCommonSubstring('ABC', '')).toBe('');\n    expect(longestCommonSubstring('', 'ABC')).toBe('');\n    expect(longestCommonSubstring('ABABC', 'BABCA')).toBe('BABC');\n    expect(longestCommonSubstring('BABCA', 'ABCBA')).toBe('ABC');\n    expect(longestCommonSubstring('sea', 'eat')).toBe('ea');\n    expect(longestCommonSubstring('algorithms', 'rithm')).toBe('rithm');\n    expect(longestCommonSubstring(\n      'Algorithms and data structures implemented in JavaScript',\n      'Here you may find Algorithms and data structures that are implemented in JavaScript',\n    )).toBe('Algorithms and data structures ');\n  });\n\n  it('should handle unicode correctly', () => {\n    expect(longestCommonSubstring('𐌵𐌵**ABC', '𐌵𐌵--ABC')).toBe('ABC');\n    expect(longestCommonSubstring('𐌵𐌵**A', '𐌵𐌵--A')).toBe('𐌵𐌵');\n    expect(longestCommonSubstring('A买B时', '买B时GD')).toBe('买B时');\n    expect(longestCommonSubstring('After test买时 case', 'another_test买时')).toBe('test买时');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/longest-common-substring/longestCommonSubstring.js",
    "content": "/**\n * Longest Common Substring (LCS) (Dynamic Programming Approach).\n *\n * @param {string} string1\n * @param {string} string2\n * @return {string}\n */\nexport default function longestCommonSubstring(string1, string2) {\n  // Convert strings to arrays to treat unicode symbols length correctly.\n  // For example:\n  // '𐌵'.length === 2\n  // [...'𐌵'].length === 1\n  const s1 = [...string1];\n  const s2 = [...string2];\n\n  // Init the matrix of all substring lengths to use Dynamic Programming approach.\n  const substringMatrix = Array(s2.length + 1).fill(null).map(() => {\n    return Array(s1.length + 1).fill(null);\n  });\n\n  // Fill the first row and first column with zeros to provide initial values.\n  for (let columnIndex = 0; columnIndex <= s1.length; columnIndex += 1) {\n    substringMatrix[0][columnIndex] = 0;\n  }\n\n  for (let rowIndex = 0; rowIndex <= s2.length; rowIndex += 1) {\n    substringMatrix[rowIndex][0] = 0;\n  }\n\n  // Build the matrix of all substring lengths to use Dynamic Programming approach.\n  let longestSubstringLength = 0;\n  let longestSubstringColumn = 0;\n  let longestSubstringRow = 0;\n\n  for (let rowIndex = 1; rowIndex <= s2.length; rowIndex += 1) {\n    for (let columnIndex = 1; columnIndex <= s1.length; columnIndex += 1) {\n      if (s1[columnIndex - 1] === s2[rowIndex - 1]) {\n        substringMatrix[rowIndex][columnIndex] = substringMatrix[rowIndex - 1][columnIndex - 1] + 1;\n      } else {\n        substringMatrix[rowIndex][columnIndex] = 0;\n      }\n\n      // Try to find the biggest length of all common substring lengths\n      // and to memorize its last character position (indices)\n      if (substringMatrix[rowIndex][columnIndex] > longestSubstringLength) {\n        longestSubstringLength = substringMatrix[rowIndex][columnIndex];\n        longestSubstringColumn = columnIndex;\n        longestSubstringRow = rowIndex;\n      }\n    }\n  }\n\n  if (longestSubstringLength === 0) {\n    // Longest common substring has not been found.\n    return '';\n  }\n\n  // Detect the longest substring from the matrix.\n  let longestSubstring = '';\n\n  while (substringMatrix[longestSubstringRow][longestSubstringColumn] > 0) {\n    longestSubstring = s1[longestSubstringColumn - 1] + longestSubstring;\n    longestSubstringRow -= 1;\n    longestSubstringColumn -= 1;\n  }\n\n  return longestSubstring;\n}\n"
  },
  {
    "path": "src/algorithms/string/palindrome/README.md",
    "content": "# Palindrome Check\n\nA [Palindrome](https://en.wikipedia.org/wiki/Palindrome) is a string that reads the same forwards and backwards.\nThis means that the second half of the string is the reverse of the\nfirst half.\n\n## Examples\n\nThe following are palindromes (thus would return `TRUE`):\n\n```\n- \"a\"\n- \"pop\"     ->  p + o + p\n- \"deed\"    ->  de + ed\n- \"kayak\"   ->  ka + y + ak\n- \"racecar\" ->  rac + e + car\n```\n\nThe following are NOT palindromes (thus would return `FALSE`):\n\n```\n- \"rad\"\n- \"dodo\"\n- \"polo\"\n```\n\n## References\n\n- [GeeksForGeeks - Check if a number is Palindrome](https://www.geeksforgeeks.org/check-if-a-number-is-palindrome/)\n"
  },
  {
    "path": "src/algorithms/string/palindrome/__test__/isPalindrome.test.js",
    "content": "import isPalindrome from '../isPalindrome';\n\ndescribe('palindromeCheck', () => {\n  it('should return whether or not the string is a palindrome', () => {\n    expect(isPalindrome('a')).toBe(true);\n    expect(isPalindrome('pop')).toBe(true);\n    expect(isPalindrome('deed')).toBe(true);\n    expect(isPalindrome('kayak')).toBe(true);\n    expect(isPalindrome('racecar')).toBe(true);\n\n    expect(isPalindrome('rad')).toBe(false);\n    expect(isPalindrome('dodo')).toBe(false);\n    expect(isPalindrome('polo')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/palindrome/isPalindrome.js",
    "content": "/**\n * @param {string} string\n * @return {boolean}\n */\n\nexport default function isPalindrome(string) {\n  let left = 0;\n  let right = string.length - 1;\n\n  while (left < right) {\n    if (string[left] !== string[right]) {\n      return false;\n    }\n    left += 1;\n    right -= 1;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "src/algorithms/string/rabin-karp/README.md",
    "content": "# Rabin Karp Algorithm\n\nIn computer science, the Rabin–Karp algorithm or Karp–Rabin algorithm \nis a string searching algorithm created by Richard M. Karp and \nMichael O. Rabin (1987) that uses hashing to find any one of a set \nof pattern strings in a text. \n\n## Algorithm\n\nThe Rabin–Karp algorithm seeks to speed up the testing of equality of \nthe pattern to the substrings in the text by using a hash function. A \nhash function is a function which converts every string into a numeric \nvalue, called its hash value; for example, we might \nhave `hash('hello') = 5`. The algorithm exploits the fact \nthat if two strings are equal, their hash values are also equal. Thus,\nstring matching is reduced (almost) to computing the hash value of the\nsearch pattern and then looking for substrings of the input string with\nthat hash value.\n\nHowever, there are two problems with this approach. First, because there\nare so many different strings and so few hash values, some differing\nstrings will have the same hash value. If the hash values match, the\npattern and the substring may not match; consequently, the potential\nmatch of search pattern and the substring must be confirmed by comparing\nthem; that comparison can take a long time for long substrings.\nLuckily, a good hash function on reasonable strings usually does not\nhave many collisions, so the expected search time will be acceptable.\n\n## Hash Function Used\n\nThe key to the Rabin–Karp algorithm's performance is the efficient computation \nof hash values of the successive substrings of the text.\nThe **Rabin fingerprint** is a popular and effective rolling hash function.\n\nThe **polynomial hash function** described in this example is not a Rabin \nfingerprint, but it works equally well. It treats every substring as a \nnumber in some base, the base being usually a large prime.\n\n## Complexity\n\nFor text of length `n` and `p` patterns of combined length `m`, its average \nand best case running time is `O(n + m)` in space `O(p)`, but its \nworst-case time is `O(n * m)`. \n\n## Application\n\nA practical application of the algorithm is detecting plagiarism. \nGiven source material, the algorithm can rapidly search through a paper \nfor instances of sentences from the source material, ignoring details \nsuch as case and punctuation. Because of the abundance of the sought \nstrings, single-string searching algorithms are impractical.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm)\n- [YouTube](https://www.youtube.com/watch?v=H4VrKHVG5qI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/algorithms/string/rabin-karp/__test__/rabinKarp.test.js",
    "content": "import rabinKarp from '../rabinKarp';\n\ndescribe('rabinKarp', () => {\n  it('should find substring in a string', () => {\n    expect(rabinKarp('', '')).toBe(0);\n    expect(rabinKarp('a', '')).toBe(0);\n    expect(rabinKarp('a', 'a')).toBe(0);\n    expect(rabinKarp('ab', 'b')).toBe(1);\n    expect(rabinKarp('abcbcglx', 'abca')).toBe(-1);\n    expect(rabinKarp('abcbcglx', 'bcgl')).toBe(3);\n    expect(rabinKarp('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toBe(15);\n    expect(rabinKarp('abcxabcdabxabcdabcdabcy', 'abcdabca')).toBe(-1);\n    expect(rabinKarp('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toBe(12);\n    expect(rabinKarp('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toBe(11);\n    expect(rabinKarp('^ !/\\'#\\'pp', ' !/\\'#\\'pp')).toBe(1);\n  });\n\n  it('should work with bigger texts', () => {\n    const text = 'Lorem Ipsum is simply dummy text of the printing and '\n    + 'typesetting industry. Lorem Ipsum has been the industry\\'s standard '\n    + 'dummy text ever since the 1500s, when an unknown printer took a '\n    + 'galley of type and scrambled it to make a type specimen book. It '\n    + 'has survived not only five centuries, but also the leap into '\n    + 'electronic typesetting, remaining essentially unchanged. It was '\n    + 'popularised in the 1960s with the release of Letraset sheets '\n    + 'containing Lorem Ipsum passages, and more recently with desktop'\n    + 'publishing software like Aldus PageMaker including versions of Lorem '\n    + 'Ipsum.';\n\n    expect(rabinKarp(text, 'Lorem')).toBe(0);\n    expect(rabinKarp(text, 'versions')).toBe(549);\n    expect(rabinKarp(text, 'versions of Lorem Ipsum.')).toBe(549);\n    expect(rabinKarp(text, 'versions of Lorem Ipsum:')).toBe(-1);\n    expect(rabinKarp(text, 'Lorem Ipsum passages, and more recently with')).toBe(446);\n  });\n\n  it('should work with UTF symbols', () => {\n    expect(rabinKarp('a\\u{ffff}', '\\u{ffff}')).toBe(1);\n    expect(rabinKarp('\\u0000耀\\u0000', '耀\\u0000')).toBe(1);\n    // @TODO: Provide Unicode support.\n    // expect(rabinKarp('a\\u{20000}', '\\u{20000}')).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/rabin-karp/rabinKarp.js",
    "content": "import PolynomialHash from '../../cryptography/polynomial-hash/PolynomialHash';\n\n/**\n * @param {string} text - Text that may contain the searchable word.\n * @param {string} word - Word that is being searched in text.\n * @return {number} - Position of the word in text.\n */\nexport default function rabinKarp(text, word) {\n  const hasher = new PolynomialHash();\n\n  // Calculate word hash that we will use for comparison with other substring hashes.\n  const wordHash = hasher.hash(word);\n\n  let prevFrame = null;\n  let currentFrameHash = null;\n\n  // Go through all substring of the text that may match.\n  for (let charIndex = 0; charIndex <= (text.length - word.length); charIndex += 1) {\n    const currentFrame = text.substring(charIndex, charIndex + word.length);\n\n    // Calculate the hash of current substring.\n    if (currentFrameHash === null) {\n      currentFrameHash = hasher.hash(currentFrame);\n    } else {\n      currentFrameHash = hasher.roll(currentFrameHash, prevFrame, currentFrame);\n    }\n\n    prevFrame = currentFrame;\n\n    // Compare the hash of current substring and seeking string.\n    // In case if hashes match let's make sure that substrings are equal.\n    // In case of hash collision the strings may not be equal.\n    if (\n      wordHash === currentFrameHash\n      && text.substr(charIndex, word.length) === word\n    ) {\n      return charIndex;\n    }\n  }\n\n  return -1;\n}\n"
  },
  {
    "path": "src/algorithms/string/regular-expression-matching/README.md",
    "content": "# Regular Expression Matching\n\nGiven an input string `s` and a pattern `p`, implement regular \nexpression matching with support for `.` and `*`.\n\n- `.` Matches any single character.\n- `*` Matches zero or more of the preceding element.\n\nThe matching should cover the **entire** input string (not partial).\n\n**Note**\n\n- `s` could be empty and contains only lowercase letters `a-z`.\n- `p` could be empty and contains only lowercase letters `a-z`, and characters like `.` or `*`.\n\n## Examples\n\n**Example #1**\n\nInput:\n```\ns = 'aa'\np = 'a'\n```\n\nOutput: `false`\n\nExplanation: `a` does not match the entire string `aa`.\n\n**Example #2**\n\nInput:\n```\ns = 'aa'\np = 'a*'\n```\n\nOutput: `true`\n\nExplanation: `*` means zero or more of the preceding element, `a`. \nTherefore, by repeating `a` once, it becomes `aa`.\n\n**Example #3**\n\nInput:\n\n```\ns = 'ab'\np = '.*'\n```\n\nOutput: `true`\n\nExplanation: `.*` means \"zero or more (`*`) of any character (`.`)\".\n\n**Example #4**\n\nInput:\n\n```\ns = 'aab'\np = 'c*a*b'\n```\n\nOutput: `true`\n\nExplanation: `c` can be repeated 0 times, `a` can be repeated \n1 time. Therefore it matches `aab`.\n\n## References\n\n- [YouTube](https://www.youtube.com/watch?v=l3hda49XcDE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=71&t=0s)\n- [LeetCode](https://leetcode.com/problems/regular-expression-matching/description/)\n"
  },
  {
    "path": "src/algorithms/string/regular-expression-matching/__test__/regularExpressionMatching.test.js",
    "content": "import regularExpressionMatching from '../regularExpressionMatching';\n\ndescribe('regularExpressionMatching', () => {\n  it('should match regular expressions in a string', () => {\n    expect(regularExpressionMatching('', '')).toBe(true);\n    expect(regularExpressionMatching('a', 'a')).toBe(true);\n    expect(regularExpressionMatching('aa', 'aa')).toBe(true);\n    expect(regularExpressionMatching('aab', 'aab')).toBe(true);\n    expect(regularExpressionMatching('aab', 'aa.')).toBe(true);\n    expect(regularExpressionMatching('aab', '.a.')).toBe(true);\n    expect(regularExpressionMatching('aab', '...')).toBe(true);\n    expect(regularExpressionMatching('a', 'a*')).toBe(true);\n    expect(regularExpressionMatching('aaa', 'a*')).toBe(true);\n    expect(regularExpressionMatching('aaab', 'a*b')).toBe(true);\n    expect(regularExpressionMatching('aaabb', 'a*b*')).toBe(true);\n    expect(regularExpressionMatching('aaabb', 'a*b*c*')).toBe(true);\n    expect(regularExpressionMatching('', 'a*')).toBe(true);\n    expect(regularExpressionMatching('xaabyc', 'xa*b.c')).toBe(true);\n    expect(regularExpressionMatching('aab', 'c*a*b*')).toBe(true);\n    expect(regularExpressionMatching('mississippi', 'mis*is*.p*.')).toBe(true);\n    expect(regularExpressionMatching('ab', '.*')).toBe(true);\n\n    expect(regularExpressionMatching('', 'a')).toBe(false);\n    expect(regularExpressionMatching('a', '')).toBe(false);\n    expect(regularExpressionMatching('aab', 'aa')).toBe(false);\n    expect(regularExpressionMatching('aab', 'baa')).toBe(false);\n    expect(regularExpressionMatching('aabc', '...')).toBe(false);\n    expect(regularExpressionMatching('aaabbdd', 'a*b*c*')).toBe(false);\n    expect(regularExpressionMatching('mississippi', 'mis*is*p*.')).toBe(false);\n    expect(regularExpressionMatching('ab', 'a*')).toBe(false);\n    expect(regularExpressionMatching('abba', 'a*b*.c')).toBe(false);\n    expect(regularExpressionMatching('abba', '.*c')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/regular-expression-matching/regularExpressionMatching.js",
    "content": "const ZERO_OR_MORE_CHARS = '*';\nconst ANY_CHAR = '.';\n\n/**\n * Dynamic programming approach.\n *\n * @param {string} string\n * @param {string} pattern\n * @return {boolean}\n */\nexport default function regularExpressionMatching(string, pattern) {\n  /*\n    * Let's initiate dynamic programming matrix for this string and pattern.\n    * We will have pattern characters on top (as columns) and string characters\n    * will be placed to the left of the table (as rows).\n    *\n    * Example:\n    *\n    *     a * b . b\n    *   - - - - - -\n    * a - - - - - -\n    * a - - - - - -\n    * b - - - - - -\n    * y - - - - - -\n    * b - - - - - -\n   */\n  const matchMatrix = Array(string.length + 1).fill(null).map(() => {\n    return Array(pattern.length + 1).fill(null);\n  });\n\n  // Let's fill the top-left cell with true. This would mean that empty\n  // string '' matches to empty pattern ''.\n  matchMatrix[0][0] = true;\n\n  // Let's fill the first row of the matrix with false. That would mean that\n  // empty string can't match any non-empty pattern.\n  //\n  // Example:\n  // string: ''\n  // pattern: 'a.z'\n  //\n  // The one exception here is patterns like a*b* that matches the empty string.\n  for (let columnIndex = 1; columnIndex <= pattern.length; columnIndex += 1) {\n    const patternIndex = columnIndex - 1;\n\n    if (pattern[patternIndex] === ZERO_OR_MORE_CHARS) {\n      matchMatrix[0][columnIndex] = matchMatrix[0][columnIndex - 2];\n    } else {\n      matchMatrix[0][columnIndex] = false;\n    }\n  }\n\n  // Let's fill the first column with false. That would mean that empty pattern\n  // can't match any non-empty string.\n  //\n  // Example:\n  // string: 'ab'\n  // pattern: ''\n  for (let rowIndex = 1; rowIndex <= string.length; rowIndex += 1) {\n    matchMatrix[rowIndex][0] = false;\n  }\n\n  // Not let's go through every letter of the pattern and every letter of\n  // the string and compare them one by one.\n  for (let rowIndex = 1; rowIndex <= string.length; rowIndex += 1) {\n    for (let columnIndex = 1; columnIndex <= pattern.length; columnIndex += 1) {\n      // Take into account that fact that matrix contain one extra column and row.\n      const stringIndex = rowIndex - 1;\n      const patternIndex = columnIndex - 1;\n\n      if (pattern[patternIndex] === ZERO_OR_MORE_CHARS) {\n        /*\n         * In case if current pattern character is special '*' character we have\n         * two options:\n         *\n         * 1. Since * char allows it previous char to not be presented in a string we\n         * need to check if string matches the pattern without '*' char and without the\n         * char that goes before '*'. That would mean to go two positions left on the\n         * same row.\n         *\n         * 2. Since * char allows it previous char to be presented in a string many times we\n         * need to check if char before * is the same as current string char. If they are the\n         * same that would mean that current string matches the current pattern in case if\n         * the string WITHOUT current char matches the same pattern. This would mean to go\n         * one position up in the same row.\n         */\n        if (matchMatrix[rowIndex][columnIndex - 2] === true) {\n          matchMatrix[rowIndex][columnIndex] = true;\n        } else if (\n          (\n            pattern[patternIndex - 1] === string[stringIndex]\n            || pattern[patternIndex - 1] === ANY_CHAR\n          )\n          && matchMatrix[rowIndex - 1][columnIndex] === true\n        ) {\n          matchMatrix[rowIndex][columnIndex] = true;\n        } else {\n          matchMatrix[rowIndex][columnIndex] = false;\n        }\n      } else if (\n        pattern[patternIndex] === string[stringIndex]\n        || pattern[patternIndex] === ANY_CHAR\n      ) {\n        /*\n         * In case if current pattern char is the same as current string char\n         * or it may be any character (in case if pattern contains '.' char)\n         * we need to check if there was a match for the pattern and for the\n         * string by WITHOUT current char. This would mean that we may copy\n         * left-top diagonal value.\n         *\n         * Example:\n         *\n         *   a b\n         * a 1 -\n         * b - 1\n         */\n        matchMatrix[rowIndex][columnIndex] = matchMatrix[rowIndex - 1][columnIndex - 1];\n      } else {\n        /*\n         * In case if pattern char and string char are different we may\n         * treat this case as \"no-match\".\n         *\n         * Example:\n         *\n         *   a b\n         * a - -\n         * c - 0\n         */\n        matchMatrix[rowIndex][columnIndex] = false;\n      }\n    }\n  }\n\n  return matchMatrix[string.length][pattern.length];\n}\n"
  },
  {
    "path": "src/algorithms/string/z-algorithm/README.md",
    "content": "# Z Algorithm\n\nThe Z-algorithm finds occurrences of a \"word\" `W` \nwithin a main \"text string\" `T` in linear time `O(|W| + |T|)`.\n\nGiven a string `S` of length `n`, the algorithm produces \nan array, `Z` where `Z[i]` represents the longest substring \nstarting from `S[i]` which is also a prefix of `S`. Finding\n`Z` for the string obtained by concatenating the word, `W` \nwith a nonce character, say `$` followed by the text, `T`,\nhelps with pattern matching, for if there is some index `i`\nsuch that `Z[i]` equals the pattern length, then the pattern\nmust be present at that point.\n\nWhile the `Z` array can be computed with two nested loops in `O(|W| * |T|)` time, the\nfollowing strategy shows how to obtain it in linear time, based \non the idea that as we iterate over the letters in the string \n(index `i` from `1` to `n - 1`), we maintain an interval `[L, R]`\nwhich is the interval with maximum `R` such that `1 ≤ L ≤ i ≤ R` \nand `S[L...R]` is a prefix that is also a substring (if no such \ninterval exists, just let `L = R =  - 1`). For `i = 1`, we can \nsimply compute `L` and `R` by comparing `S[0...]` to `S[1...]`.\n\n**Example of Z array**\n\n```\nIndex            0   1   2   3   4   5   6   7   8   9  10  11 \nText             a   a   b   c   a   a   b   x   a   a   a   z\nZ values         X   1   0   0   3   1   0   0   2   2   1   0 \n```\n\nOther examples\n\n```\nstr =  a a a a a a\nZ[] =  x 5 4 3 2 1\n```\n\n```\nstr =  a a b a a c d\nZ[] =  x 1 0 2 1 0 0\n```\n\n```\nstr =  a b a b a b a b\nZ[] =  x 0 6 0 4 0 2 0\n```\n\n**Example of Z box**\n\n![z-box](https://ivanyu.me/wp-content/uploads/2014/09/zalg1.png)\n\n## Complexity\n\n- **Time:** `O(|W| + |T|)`\n- **Space:** `O(|W|)`\n\n## References\n\n- [GeeksForGeeks](https://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/)\n- [YouTube](https://www.youtube.com/watch?v=CpZh4eF8QBw&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=70)\n- [Z Algorithm by Ivan Yurchenko](https://ivanyu.me/blog/2013/10/15/z-algorithm/)\n"
  },
  {
    "path": "src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js",
    "content": "import zAlgorithm from '../zAlgorithm';\n\ndescribe('zAlgorithm', () => {\n  it('should find word positions in given text', () => {\n    expect(zAlgorithm('abcbcglx', 'abca')).toEqual([]);\n    expect(zAlgorithm('abca', 'abca')).toEqual([0]);\n    expect(zAlgorithm('abca', 'abcadfd')).toEqual([]);\n    expect(zAlgorithm('abcbcglabcx', 'abc')).toEqual([0, 7]);\n    expect(zAlgorithm('abcbcglx', 'bcgl')).toEqual([3]);\n    expect(zAlgorithm('abcbcglx', 'cglx')).toEqual([4]);\n    expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toEqual([15]);\n    expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabca')).toEqual([]);\n    expect(zAlgorithm('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toEqual([12]);\n    expect(zAlgorithm('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toEqual([11]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/string/z-algorithm/zAlgorithm.js",
    "content": "// The string separator that is being used for \"word\" and \"text\" concatenation.\nconst SEPARATOR = '$';\n\n/**\n * @param {string} zString\n * @return {number[]}\n */\nfunction buildZArray(zString) {\n  // Initiate zArray and fill it with zeros.\n  const zArray = new Array(zString.length).fill(null).map(() => 0);\n\n  // Z box boundaries.\n  let zBoxLeftIndex = 0;\n  let zBoxRightIndex = 0;\n\n  // Position of current zBox character that is also a position of\n  // the same character in prefix.\n  // For example:\n  // Z string: ab$xxabxx\n  // Indices:  012345678\n  // Prefix:   ab.......\n  // Z box:    .....ab..\n  // Z box shift for 'a' would be 0 (0-position in prefix and 0-position in Z box)\n  // Z box shift for 'b' would be 1 (1-position in prefix and 1-position in Z box)\n  let zBoxShift = 0;\n\n  // Go through all characters of the zString.\n  for (let charIndex = 1; charIndex < zString.length; charIndex += 1) {\n    if (charIndex > zBoxRightIndex) {\n      // We're OUTSIDE of Z box. In other words this is a case when we're\n      // starting from Z box of size 1.\n\n      // In this case let's make current character to be a Z box of length 1.\n      zBoxLeftIndex = charIndex;\n      zBoxRightIndex = charIndex;\n\n      // Now let's go and check current and the following characters to see if\n      // they are the same as a prefix. By doing this we will also expand our\n      // Z box. For example if starting from current position we will find 3\n      // more characters that are equal to the ones in the prefix we will expand\n      // right Z box boundary by 3.\n      while (\n        zBoxRightIndex < zString.length\n        && zString[zBoxRightIndex - zBoxLeftIndex] === zString[zBoxRightIndex]\n      ) {\n        // Expanding Z box right boundary.\n        zBoxRightIndex += 1;\n      }\n\n      // Now we may calculate how many characters starting from current position\n      // are are the same as the prefix. We may calculate it by difference between\n      // right and left Z box boundaries.\n      zArray[charIndex] = zBoxRightIndex - zBoxLeftIndex;\n\n      // Move right Z box boundary left by one position just because we've used\n      // [zBoxRightIndex - zBoxLeftIndex] index calculation above.\n      zBoxRightIndex -= 1;\n    } else {\n      // We're INSIDE of Z box.\n\n      // Calculate corresponding Z box shift. Because we want to copy the values\n      // from zArray that have been calculated before.\n      zBoxShift = charIndex - zBoxLeftIndex;\n\n      // Check if the value that has been already calculated before\n      // leaves us inside of Z box or it goes beyond the checkbox\n      // right boundary.\n      if (zArray[zBoxShift] < (zBoxRightIndex - charIndex) + 1) {\n        // If calculated value don't force us to go outside Z box\n        // then we're safe and we may simply use previously calculated value.\n        zArray[charIndex] = zArray[zBoxShift];\n      } else {\n        // In case if previously calculated values forces us to go outside of Z box\n        // we can't safely copy previously calculated zArray value. It is because\n        // we are sure that there is no further prefix matches outside of Z box.\n        // Thus such values must be re-calculated and reduced to certain point.\n\n        // To do so we need to shift left boundary of Z box to current position.\n        zBoxLeftIndex = charIndex;\n\n        // And start comparing characters one by one as we normally do for the case\n        // when we are outside of checkbox.\n        while (\n          zBoxRightIndex < zString.length\n          && zString[zBoxRightIndex - zBoxLeftIndex] === zString[zBoxRightIndex]\n        ) {\n          zBoxRightIndex += 1;\n        }\n\n        zArray[charIndex] = zBoxRightIndex - zBoxLeftIndex;\n\n        zBoxRightIndex -= 1;\n      }\n    }\n  }\n\n  // Return generated zArray.\n  return zArray;\n}\n\n/**\n * @param {string} text\n * @param {string} word\n * @return {number[]}\n */\nexport default function zAlgorithm(text, word) {\n  // The list of word's positions in text. Word may be found in the same text\n  // in several different positions. Thus it is an array.\n  const wordPositions = [];\n\n  // Concatenate word and string. Word will be a prefix to a string.\n  const zString = `${word}${SEPARATOR}${text}`;\n\n  // Generate Z-array for concatenated string.\n  const zArray = buildZArray(zString);\n\n  // Based on Z-array properties each cell will tell us the length of the match between\n  // the string prefix and current sub-text. Thus we're may find all positions in zArray\n  // with the number that equals to the length of the word (zString prefix) and based on\n  // that positions we'll be able to calculate word positions in text.\n  for (let charIndex = 1; charIndex < zArray.length; charIndex += 1) {\n    if (zArray[charIndex] === word.length) {\n      // Since we did concatenation to form zString we need to subtract prefix\n      // and separator lengths.\n      const wordPosition = charIndex - word.length - SEPARATOR.length;\n      wordPositions.push(wordPosition);\n    }\n  }\n\n  // Return the list of word positions.\n  return wordPositions;\n}\n"
  },
  {
    "path": "src/algorithms/tree/breadth-first-search/README.md",
    "content": "# Breadth-First Search (BFS)\n\nBreadth-first search (BFS) is an algorithm for traversing \nor searching tree or graph data structures. It starts at\nthe tree root (or some arbitrary node of a graph, sometimes \nreferred to as a 'search key') and explores the neighbor\nnodes first, before moving to the next level neighbors.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif)\n\n## Pseudocode\n\n```text\nBFS(root)\n  Pre: root is the node of the BST\n  Post: the nodes in the BST have been visited in breadth first order\n  q ← queue\n  while root = ø\n    yield root.value\n    if root.left = ø\n      q.enqueue(root.left)\n    end if\n    if root.right = ø\n      q.enqueue(root.right)\n    end if\n    if !q.isEmpty()\n      root ← q.dequeue()\n    else\n      root ← ø\n    end if\n  end while\nend BFS\n```\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search)\n- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)\n- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)\n"
  },
  {
    "path": "src/algorithms/tree/breadth-first-search/__test__/breadthFirstSearch.test.js",
    "content": "import BinaryTreeNode from '../../../../data-structures/tree/BinaryTreeNode';\nimport breadthFirstSearch from '../breadthFirstSearch';\n\ndescribe('breadthFirstSearch', () => {\n  it('should perform BFS operation on tree', () => {\n    const nodeA = new BinaryTreeNode('A');\n    const nodeB = new BinaryTreeNode('B');\n    const nodeC = new BinaryTreeNode('C');\n    const nodeD = new BinaryTreeNode('D');\n    const nodeE = new BinaryTreeNode('E');\n    const nodeF = new BinaryTreeNode('F');\n    const nodeG = new BinaryTreeNode('G');\n\n    nodeA.setLeft(nodeB).setRight(nodeC);\n    nodeB.setLeft(nodeD).setRight(nodeE);\n    nodeC.setLeft(nodeF).setRight(nodeG);\n\n    // In-order traversing.\n    expect(nodeA.toString()).toBe('D,B,E,A,F,C,G');\n\n    const enterNodeCallback = jest.fn();\n    const leaveNodeCallback = jest.fn();\n\n    // Traverse tree without callbacks first to check default ones.\n    breadthFirstSearch(nodeA);\n\n    // Traverse tree with callbacks.\n    breadthFirstSearch(nodeA, {\n      enterNode: enterNodeCallback,\n      leaveNode: leaveNodeCallback,\n    });\n\n    expect(enterNodeCallback).toHaveBeenCalledTimes(7);\n    expect(leaveNodeCallback).toHaveBeenCalledTimes(7);\n\n    // Check node entering.\n    expect(enterNodeCallback.mock.calls[0][0].value).toEqual('A');\n    expect(enterNodeCallback.mock.calls[1][0].value).toEqual('B');\n    expect(enterNodeCallback.mock.calls[2][0].value).toEqual('C');\n    expect(enterNodeCallback.mock.calls[3][0].value).toEqual('D');\n    expect(enterNodeCallback.mock.calls[4][0].value).toEqual('E');\n    expect(enterNodeCallback.mock.calls[5][0].value).toEqual('F');\n    expect(enterNodeCallback.mock.calls[6][0].value).toEqual('G');\n\n    // Check node leaving.\n    expect(leaveNodeCallback.mock.calls[0][0].value).toEqual('A');\n    expect(leaveNodeCallback.mock.calls[1][0].value).toEqual('B');\n    expect(leaveNodeCallback.mock.calls[2][0].value).toEqual('C');\n    expect(leaveNodeCallback.mock.calls[3][0].value).toEqual('D');\n    expect(leaveNodeCallback.mock.calls[4][0].value).toEqual('E');\n    expect(leaveNodeCallback.mock.calls[5][0].value).toEqual('F');\n    expect(leaveNodeCallback.mock.calls[6][0].value).toEqual('G');\n  });\n\n  it('allow users to redefine node visiting logic', () => {\n    const nodeA = new BinaryTreeNode('A');\n    const nodeB = new BinaryTreeNode('B');\n    const nodeC = new BinaryTreeNode('C');\n    const nodeD = new BinaryTreeNode('D');\n    const nodeE = new BinaryTreeNode('E');\n    const nodeF = new BinaryTreeNode('F');\n    const nodeG = new BinaryTreeNode('G');\n\n    nodeA.setLeft(nodeB).setRight(nodeC);\n    nodeB.setLeft(nodeD).setRight(nodeE);\n    nodeC.setLeft(nodeF).setRight(nodeG);\n\n    // In-order traversing.\n    expect(nodeA.toString()).toBe('D,B,E,A,F,C,G');\n\n    const enterNodeCallback = jest.fn();\n    const leaveNodeCallback = jest.fn();\n\n    // Traverse tree without callbacks first to check default ones.\n    breadthFirstSearch(nodeA);\n\n    // Traverse tree with callbacks.\n    breadthFirstSearch(nodeA, {\n      allowTraversal: (node, child) => {\n        // Forbid traversing left half of the tree.\n        return child.value !== 'B';\n      },\n      enterNode: enterNodeCallback,\n      leaveNode: leaveNodeCallback,\n    });\n\n    expect(enterNodeCallback).toHaveBeenCalledTimes(4);\n    expect(leaveNodeCallback).toHaveBeenCalledTimes(4);\n\n    // Check node entering.\n    expect(enterNodeCallback.mock.calls[0][0].value).toEqual('A');\n    expect(enterNodeCallback.mock.calls[1][0].value).toEqual('C');\n    expect(enterNodeCallback.mock.calls[2][0].value).toEqual('F');\n    expect(enterNodeCallback.mock.calls[3][0].value).toEqual('G');\n\n    // Check node leaving.\n    expect(leaveNodeCallback.mock.calls[0][0].value).toEqual('A');\n    expect(leaveNodeCallback.mock.calls[1][0].value).toEqual('C');\n    expect(leaveNodeCallback.mock.calls[2][0].value).toEqual('F');\n    expect(leaveNodeCallback.mock.calls[3][0].value).toEqual('G');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/tree/breadth-first-search/breadthFirstSearch.js",
    "content": "import Queue from '../../../data-structures/queue/Queue';\n\n/**\n * @typedef {Object} Callbacks\n * @property {function(node: BinaryTreeNode, child: BinaryTreeNode): boolean} allowTraversal -\n *   Determines whether BFS should traverse from the node to its child.\n * @property {function(node: BinaryTreeNode)} enterNode - Called when BFS enters the node.\n * @property {function(node: BinaryTreeNode)} leaveNode - Called when BFS leaves the node.\n */\n\n/**\n * @param {Callbacks} [callbacks]\n * @returns {Callbacks}\n */\nfunction initCallbacks(callbacks = {}) {\n  const initiatedCallback = callbacks;\n\n  const stubCallback = () => {};\n  const defaultAllowTraversal = () => true;\n\n  initiatedCallback.allowTraversal = callbacks.allowTraversal || defaultAllowTraversal;\n  initiatedCallback.enterNode = callbacks.enterNode || stubCallback;\n  initiatedCallback.leaveNode = callbacks.leaveNode || stubCallback;\n\n  return initiatedCallback;\n}\n\n/**\n * @param {BinaryTreeNode} rootNode\n * @param {Callbacks} [originalCallbacks]\n */\nexport default function breadthFirstSearch(rootNode, originalCallbacks) {\n  const callbacks = initCallbacks(originalCallbacks);\n  const nodeQueue = new Queue();\n\n  // Do initial queue setup.\n  nodeQueue.enqueue(rootNode);\n\n  while (!nodeQueue.isEmpty()) {\n    const currentNode = nodeQueue.dequeue();\n\n    callbacks.enterNode(currentNode);\n\n    // Add all children to the queue for future traversals.\n\n    // Traverse left branch.\n    if (currentNode.left && callbacks.allowTraversal(currentNode, currentNode.left)) {\n      nodeQueue.enqueue(currentNode.left);\n    }\n\n    // Traverse right branch.\n    if (currentNode.right && callbacks.allowTraversal(currentNode, currentNode.right)) {\n      nodeQueue.enqueue(currentNode.right);\n    }\n\n    callbacks.leaveNode(currentNode);\n  }\n}\n"
  },
  {
    "path": "src/algorithms/tree/depth-first-search/README.md",
    "content": "# Depth-First Search (DFS)\n\nDepth-first search (DFS) is an algorithm for traversing or \nsearching tree or graph data structures. One starts at \nthe root (selecting some arbitrary node as the root in \nthe case of a graph) and explores as far as possible \nalong each branch before backtracking.\n\n![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search)\n- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)\n- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)\n"
  },
  {
    "path": "src/algorithms/tree/depth-first-search/__test__/depthFirstSearch.test.js",
    "content": "import BinaryTreeNode from '../../../../data-structures/tree/BinaryTreeNode';\nimport depthFirstSearch from '../depthFirstSearch';\n\ndescribe('depthFirstSearch', () => {\n  it('should perform DFS operation on tree', () => {\n    const nodeA = new BinaryTreeNode('A');\n    const nodeB = new BinaryTreeNode('B');\n    const nodeC = new BinaryTreeNode('C');\n    const nodeD = new BinaryTreeNode('D');\n    const nodeE = new BinaryTreeNode('E');\n    const nodeF = new BinaryTreeNode('F');\n    const nodeG = new BinaryTreeNode('G');\n\n    nodeA.setLeft(nodeB).setRight(nodeC);\n    nodeB.setLeft(nodeD).setRight(nodeE);\n    nodeC.setLeft(nodeF).setRight(nodeG);\n\n    // In-order traversing.\n    expect(nodeA.toString()).toBe('D,B,E,A,F,C,G');\n\n    const enterNodeCallback = jest.fn();\n    const leaveNodeCallback = jest.fn();\n\n    // Traverse tree without callbacks first to check default ones.\n    depthFirstSearch(nodeA);\n\n    // Traverse tree with callbacks.\n    depthFirstSearch(nodeA, {\n      enterNode: enterNodeCallback,\n      leaveNode: leaveNodeCallback,\n    });\n\n    expect(enterNodeCallback).toHaveBeenCalledTimes(7);\n    expect(leaveNodeCallback).toHaveBeenCalledTimes(7);\n\n    // Check node entering.\n    expect(enterNodeCallback.mock.calls[0][0].value).toEqual('A');\n    expect(enterNodeCallback.mock.calls[1][0].value).toEqual('B');\n    expect(enterNodeCallback.mock.calls[2][0].value).toEqual('D');\n    expect(enterNodeCallback.mock.calls[3][0].value).toEqual('E');\n    expect(enterNodeCallback.mock.calls[4][0].value).toEqual('C');\n    expect(enterNodeCallback.mock.calls[5][0].value).toEqual('F');\n    expect(enterNodeCallback.mock.calls[6][0].value).toEqual('G');\n\n    // Check node leaving.\n    expect(leaveNodeCallback.mock.calls[0][0].value).toEqual('D');\n    expect(leaveNodeCallback.mock.calls[1][0].value).toEqual('E');\n    expect(leaveNodeCallback.mock.calls[2][0].value).toEqual('B');\n    expect(leaveNodeCallback.mock.calls[3][0].value).toEqual('F');\n    expect(leaveNodeCallback.mock.calls[4][0].value).toEqual('G');\n    expect(leaveNodeCallback.mock.calls[5][0].value).toEqual('C');\n    expect(leaveNodeCallback.mock.calls[6][0].value).toEqual('A');\n  });\n\n  it('allow users to redefine node visiting logic', () => {\n    const nodeA = new BinaryTreeNode('A');\n    const nodeB = new BinaryTreeNode('B');\n    const nodeC = new BinaryTreeNode('C');\n    const nodeD = new BinaryTreeNode('D');\n    const nodeE = new BinaryTreeNode('E');\n    const nodeF = new BinaryTreeNode('F');\n    const nodeG = new BinaryTreeNode('G');\n\n    nodeA.setLeft(nodeB).setRight(nodeC);\n    nodeB.setLeft(nodeD).setRight(nodeE);\n    nodeC.setLeft(nodeF).setRight(nodeG);\n\n    // In-order traversing.\n    expect(nodeA.toString()).toBe('D,B,E,A,F,C,G');\n\n    const enterNodeCallback = jest.fn();\n    const leaveNodeCallback = jest.fn();\n\n    // Traverse tree without callbacks first to check default ones.\n    depthFirstSearch(nodeA);\n\n    // Traverse tree with callbacks.\n    depthFirstSearch(nodeA, {\n      allowTraversal: (node, child) => {\n        // Forbid traversing left part of the tree.\n        return child.value !== 'B';\n      },\n      enterNode: enterNodeCallback,\n      leaveNode: leaveNodeCallback,\n    });\n\n    expect(enterNodeCallback).toHaveBeenCalledTimes(4);\n    expect(leaveNodeCallback).toHaveBeenCalledTimes(4);\n\n    // Check node entering.\n    expect(enterNodeCallback.mock.calls[0][0].value).toEqual('A');\n    expect(enterNodeCallback.mock.calls[1][0].value).toEqual('C');\n    expect(enterNodeCallback.mock.calls[2][0].value).toEqual('F');\n    expect(enterNodeCallback.mock.calls[3][0].value).toEqual('G');\n\n    // Check node leaving.\n    expect(leaveNodeCallback.mock.calls[0][0].value).toEqual('F');\n    expect(leaveNodeCallback.mock.calls[1][0].value).toEqual('G');\n    expect(leaveNodeCallback.mock.calls[2][0].value).toEqual('C');\n    expect(leaveNodeCallback.mock.calls[3][0].value).toEqual('A');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/tree/depth-first-search/depthFirstSearch.js",
    "content": "/**\n * @typedef {Object} TraversalCallbacks\n *\n * @property {function(node: BinaryTreeNode, child: BinaryTreeNode): boolean} allowTraversal\n * - Determines whether DFS should traverse from the node to its child.\n *\n * @property {function(node: BinaryTreeNode)} enterNode - Called when DFS enters the node.\n *\n * @property {function(node: BinaryTreeNode)} leaveNode - Called when DFS leaves the node.\n */\n\n/**\n * Extend missing traversal callbacks with default callbacks.\n *\n * @param {TraversalCallbacks} [callbacks] - The object that contains traversal callbacks.\n * @returns {TraversalCallbacks} - Traversal callbacks extended with defaults callbacks.\n */\nfunction initCallbacks(callbacks = {}) {\n  // Init empty callbacks object.\n  const initiatedCallbacks = {};\n\n  // Empty callback that we will use in case if user didn't provide real callback function.\n  const stubCallback = () => {};\n  // By default we will allow traversal of every node\n  // in case if user didn't provide a callback for that.\n  const defaultAllowTraversalCallback = () => true;\n\n  // Copy original callbacks to our initiatedCallbacks object or use default callbacks instead.\n  initiatedCallbacks.allowTraversal = callbacks.allowTraversal || defaultAllowTraversalCallback;\n  initiatedCallbacks.enterNode = callbacks.enterNode || stubCallback;\n  initiatedCallbacks.leaveNode = callbacks.leaveNode || stubCallback;\n\n  // Returned processed list of callbacks.\n  return initiatedCallbacks;\n}\n\n/**\n * Recursive depth-first-search traversal for binary.\n *\n * @param {BinaryTreeNode} node - binary tree node that we will start traversal from.\n * @param {TraversalCallbacks} callbacks - the object that contains traversal callbacks.\n */\nexport function depthFirstSearchRecursive(node, callbacks) {\n  // Call the \"enterNode\" callback to notify that the node is going to be entered.\n  callbacks.enterNode(node);\n\n  // Traverse left branch only if case if traversal of the left node is allowed.\n  if (node.left && callbacks.allowTraversal(node, node.left)) {\n    depthFirstSearchRecursive(node.left, callbacks);\n  }\n\n  // Traverse right branch only if case if traversal of the right node is allowed.\n  if (node.right && callbacks.allowTraversal(node, node.right)) {\n    depthFirstSearchRecursive(node.right, callbacks);\n  }\n\n  // Call the \"leaveNode\" callback to notify that traversal\n  // of the current node and its children is finished.\n  callbacks.leaveNode(node);\n}\n\n/**\n * Perform depth-first-search traversal of the rootNode.\n * For every traversal step call \"allowTraversal\", \"enterNode\" and \"leaveNode\" callbacks.\n * See TraversalCallbacks type definition for more details about the shape of callbacks object.\n *\n * @param {BinaryTreeNode} rootNode - The node from which we start traversing.\n * @param {TraversalCallbacks} [callbacks] - Traversal callbacks.\n */\nexport default function depthFirstSearch(rootNode, callbacks) {\n  // In case if user didn't provide some callback we need to replace them with default ones.\n  const processedCallbacks = initCallbacks(callbacks);\n\n  // Now, when we have all necessary callbacks we may proceed to recursive traversal.\n  depthFirstSearchRecursive(rootNode, processedCallbacks);\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md",
    "content": "# Best Time to Buy and Sell Stock\n\n## Task Description\n\nSay you have an array prices for which the `i`-th element is the price of a given stock on day `i`.\n\nFind 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).\n\n> Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).\n\n**Example #1**\n\n```\nInput: [7, 1, 5, 3, 6, 4]\nOutput: 7\n```\n\n_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`.\n\n**Example #2**\n\n```\nInput: [1, 2, 3, 4, 5]\nOutput: 4\n```\n\n_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.\n\n**Example #3**\n\n```\nInput: [7, 6, 4, 3, 1]\nOutput: 0\n```\n\n_Explanation:_ In this case, no transaction is done, i.e. max `profit = 0`.\n\n## Possible Solutions\n\n### Divide and conquer approach `O(2^n)`\n\nWe may try **all** combinations of buying and selling and find out the most profitable one by applying _divide and conquer approach_.\n\nLet'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:\n\n1. _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])`.\n2. _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])`.\n\nThe overall profit would be equal to → `overallProfit = Max(keepProfit, buySellProfit)`.\n\nAs you can see the `profit([6, 4, 3, 1])` task is being solved in the same recursive manner.\n\n> See the full code example in [dqBestTimeToBuySellStocks.js](dqBestTimeToBuySellStocks.js)\n\n#### Time Complexity\n\nAs 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)`.\n\nAs you may see, this is very inefficient. For example for just `20` prices the number of recursive calls will be somewhere close to `2M`!\n\n#### Additional Space Complexity\n\nIf 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\n## Peak Valley Approach `O(n)`\n\nIf 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\n![Peak Valley Approach](https://leetcode.com/media/original_images/122_maxprofit_1.PNG)\n\n_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_\n\nSo, 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).\n\n> See the full code example in [peakvalleyBestTimeToBuySellStocks.js](peakvalleyBestTimeToBuySellStocks.js)\n\n#### Time Complexity\n\nSince the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`.\n\n#### Additional Space Complexity\n\nExcept of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`.\n\n## Accumulator Approach `O(n)`\n\nThere 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]`:\n\n![Simple One Pass](https://leetcode.com/media/original_images/122_maxprofit_2.PNG)\n\n_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_\n\nYou 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,\n\n> See the full code example in [accumulatorBestTimeToBuySellStocks.js](accumulatorBestTimeToBuySellStocks.js)\n\n#### Time Complexity\n\nSince the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`.\n\n#### Additional Space Complexity\n\nExcept of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`.\n\n## References\n\n- [Best Time to Buy and Sell Stock on LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js",
    "content": "import accumulatorBestTimeToBuySellStocks from '../accumulatorBestTimeToBuySellStocks';\n\ndescribe('accumulatorBestTimeToBuySellStocks', () => {\n  it('should find the best time to buy and sell stocks', () => {\n    let visit;\n\n    expect(accumulatorBestTimeToBuySellStocks([1, 5])).toEqual(4);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(1);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([1, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(2);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([5, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(2);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9);\n    expect(visit).toHaveBeenCalledTimes(3);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25);\n    expect(visit).toHaveBeenCalledTimes(6);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7);\n    expect(visit).toHaveBeenCalledTimes(6);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(5);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(5);\n\n    visit = jest.fn();\n    expect(accumulatorBestTimeToBuySellStocks(\n      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],\n      visit,\n    )).toEqual(19);\n    expect(visit).toHaveBeenCalledTimes(20);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js",
    "content": "import dpBestTimeToBuySellStocks from '../dpBestTimeToBuySellStocks';\n\ndescribe('dpBestTimeToBuySellStocks', () => {\n  it('should find the best time to buy and sell stocks', () => {\n    let visit;\n\n    expect(dpBestTimeToBuySellStocks([1, 5])).toEqual(4);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(1);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([1, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(2);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([5, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(2);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9);\n    expect(visit).toHaveBeenCalledTimes(3);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25);\n    expect(visit).toHaveBeenCalledTimes(6);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7);\n    expect(visit).toHaveBeenCalledTimes(6);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(5);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(5);\n\n    visit = jest.fn();\n    expect(dpBestTimeToBuySellStocks(\n      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],\n      visit,\n    )).toEqual(19);\n    expect(visit).toHaveBeenCalledTimes(20);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js",
    "content": "import dqBestTimeToBuySellStocks from '../dqBestTimeToBuySellStocks';\n\ndescribe('dqBestTimeToBuySellStocks', () => {\n  it('should find the best time to buy and sell stocks', () => {\n    let visit;\n\n    expect(dqBestTimeToBuySellStocks([1, 5])).toEqual(4);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(3);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([1, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(7);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([5, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(7);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9);\n    expect(visit).toHaveBeenCalledTimes(15);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25);\n    expect(visit).toHaveBeenCalledTimes(127);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7);\n    expect(visit).toHaveBeenCalledTimes(127);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(63);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(63);\n\n    visit = jest.fn();\n    expect(dqBestTimeToBuySellStocks(\n      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],\n      visit,\n    )).toEqual(19);\n    expect(visit).toHaveBeenCalledTimes(2097151);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js",
    "content": "import peakvalleyBestTimeToBuySellStocks from '../peakvalleyBestTimeToBuySellStocks';\n\ndescribe('peakvalleyBestTimeToBuySellStocks', () => {\n  it('should find the best time to buy and sell stocks', () => {\n    let visit;\n\n    expect(peakvalleyBestTimeToBuySellStocks([1, 5])).toEqual(4);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(1);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([1, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(2);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([5, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(2);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9);\n    expect(visit).toHaveBeenCalledTimes(3);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25);\n    expect(visit).toHaveBeenCalledTimes(6);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7);\n    expect(visit).toHaveBeenCalledTimes(6);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4);\n    expect(visit).toHaveBeenCalledTimes(5);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0);\n    expect(visit).toHaveBeenCalledTimes(5);\n\n    visit = jest.fn();\n    expect(peakvalleyBestTimeToBuySellStocks(\n      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],\n      visit,\n    )).toEqual(19);\n    expect(visit).toHaveBeenCalledTimes(20);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js",
    "content": "/**\n * Finds the maximum profit from selling and buying the stocks.\n * ACCUMULATOR APPROACH.\n *\n * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1]\n * @param {function(): void} visit - Visiting callback to calculate the number of iterations.\n * @return {number} - The maximum profit\n */\nconst accumulatorBestTimeToBuySellStocks = (prices, visit = () => {}) => {\n  visit();\n  let profit = 0;\n  for (let day = 1; day < prices.length; day += 1) {\n    visit();\n    // Add the increase of the price from yesterday till today (if there was any) to the profit.\n    profit += Math.max(prices[day] - prices[day - 1], 0);\n  }\n  return profit;\n};\n\nexport default accumulatorBestTimeToBuySellStocks;\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js",
    "content": "/**\n * Finds the maximum profit from selling and buying the stocks.\n * DYNAMIC PROGRAMMING APPROACH.\n *\n * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1]\n * @param {function(): void} visit - Visiting callback to calculate the number of iterations.\n * @return {number} - The maximum profit\n */\nconst dpBestTimeToBuySellStocks = (prices, visit = () => {}) => {\n  visit();\n  let lastBuy = -prices[0];\n  let lastSold = 0;\n\n  for (let day = 1; day < prices.length; day += 1) {\n    visit();\n    const curBuy = Math.max(lastBuy, lastSold - prices[day]);\n    const curSold = Math.max(lastSold, lastBuy + prices[day]);\n    lastBuy = curBuy;\n    lastSold = curSold;\n  }\n\n  return lastSold;\n};\n\nexport default dpBestTimeToBuySellStocks;\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js",
    "content": "/**\n * Finds the maximum profit from selling and buying the stocks.\n * DIVIDE & CONQUER APPROACH.\n *\n * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1]\n * @param {function(): void} visit - Visiting callback to calculate the number of iterations.\n * @return {number} - The maximum profit\n */\nconst dqBestTimeToBuySellStocks = (prices, visit = () => {}) => {\n  /**\n   * Recursive implementation of the main function. It is hidden from the users.\n   *\n   * @param {boolean} buy - Whether we're allow to sell or to buy now\n   * @param {number} day - Current day of trading (current index of prices array)\n   * @returns {number} - Max profit from buying/selling\n   */\n  const recursiveBuyerSeller = (buy, day) => {\n    // Registering the recursive call visit to calculate the complexity.\n    visit();\n\n    // Quitting the recursion if this is the last day of trading (prices array ended).\n    if (day === prices.length) {\n      return 0;\n    }\n\n    // If we're buying - we're loosing money (-1), if we're selling we're getting money (+1).\n    const operationSign = buy ? -1 : +1;\n    return Math.max(\n      // Option 1: Don't do anything.\n      recursiveBuyerSeller(buy, day + 1),\n      // Option 2: Sell or Buy at the current price.\n      operationSign * prices[day] + recursiveBuyerSeller(!buy, day + 1),\n    );\n  };\n\n  const buy = true;\n  const day = 0;\n\n  return recursiveBuyerSeller(buy, day);\n};\n\nexport default dqBestTimeToBuySellStocks;\n"
  },
  {
    "path": "src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js",
    "content": "/**\n * Finds the maximum profit from selling and buying the stocks.\n * PEAK VALLEY APPROACH.\n *\n * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1]\n * @param {function(): void} visit - Visiting callback to calculate the number of iterations.\n * @return {number} - The maximum profit\n */\nconst peakvalleyBestTimeToBuySellStocks = (prices, visit = () => {}) => {\n  visit();\n  let profit = 0;\n  let low = prices[0];\n  let high = prices[0];\n\n  prices.slice(1).forEach((currentPrice) => {\n    visit();\n    if (currentPrice < high) {\n      // If price went down, we need to sell.\n      profit += high - low;\n      low = currentPrice;\n      high = currentPrice;\n    } else {\n      // If price went up, we don't need to do anything but increase a high record.\n      high = currentPrice;\n    }\n  });\n\n  // In case if price went up during the last day\n  // and we didn't have chance to sell inside the forEach loop.\n  profit += high - low;\n\n  return profit;\n};\n\nexport default peakvalleyBestTimeToBuySellStocks;\n"
  },
  {
    "path": "src/algorithms/uncategorized/hanoi-tower/README.md",
    "content": "# Tower of Hanoi\n\nThe Tower of Hanoi (also called the Tower of Brahma or Lucas'\nTower and sometimes pluralized) is a mathematical game or puzzle. \nIt consists of three rods and a number of disks of different sizes,\nwhich can slide onto any rod. The puzzle starts with the disks in \na neat stack in ascending order of size on one rod, the smallest \nat the top, thus making a conical shape.\n\nThe objective of the puzzle is to move the entire stack to another \nrod, obeying the following simple rules:\n\n- Only one disk can be moved at a time.\n- Each move consists of taking the upper disk from one of the \nstacks and placing it on top of another stack or on an empty rod.\n- No disk may be placed on top of a smaller disk.\n\n![Hanoi Tower](https://upload.wikimedia.org/wikipedia/commons/8/8d/Iterative_algorithm_solving_a_6_disks_Tower_of_Hanoi.gif)\n\nAnimation of an iterative algorithm solving 6-disk problem\n\nWith `3` disks, the puzzle can be solved in `7` moves. The minimal \nnumber of moves required to solve a Tower of Hanoi puzzle \nis `2^n − 1`, where `n` is the number of disks.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Tower_of_Hanoi)\n- [HackerEarth](https://www.hackerearth.com/blog/algorithms/tower-hanoi-recursion-game-algorithm-explained/)\n"
  },
  {
    "path": "src/algorithms/uncategorized/hanoi-tower/__test__/hanoiTower.test.js",
    "content": "import hanoiTower from '../hanoiTower';\nimport Stack from '../../../../data-structures/stack/Stack';\n\ndescribe('hanoiTower', () => {\n  it('should solve tower of hanoi puzzle with 2 discs', () => {\n    const moveCallback = jest.fn();\n    const numberOfDiscs = 2;\n\n    const fromPole = new Stack();\n    const withPole = new Stack();\n    const toPole = new Stack();\n\n    hanoiTower({\n      numberOfDiscs,\n      moveCallback,\n      fromPole,\n      withPole,\n      toPole,\n    });\n\n    expect(moveCallback).toHaveBeenCalledTimes((2 ** numberOfDiscs) - 1);\n\n    expect(fromPole.toArray()).toEqual([]);\n    expect(toPole.toArray()).toEqual([1, 2]);\n\n    expect(moveCallback.mock.calls[0][0]).toBe(1);\n    expect(moveCallback.mock.calls[0][1]).toEqual([1, 2]);\n    expect(moveCallback.mock.calls[0][2]).toEqual([]);\n\n    expect(moveCallback.mock.calls[1][0]).toBe(2);\n    expect(moveCallback.mock.calls[1][1]).toEqual([2]);\n    expect(moveCallback.mock.calls[1][2]).toEqual([]);\n\n    expect(moveCallback.mock.calls[2][0]).toBe(1);\n    expect(moveCallback.mock.calls[2][1]).toEqual([1]);\n    expect(moveCallback.mock.calls[2][2]).toEqual([2]);\n  });\n\n  it('should solve tower of hanoi puzzle with 3 discs', () => {\n    const moveCallback = jest.fn();\n    const numberOfDiscs = 3;\n\n    hanoiTower({\n      numberOfDiscs,\n      moveCallback,\n    });\n\n    expect(moveCallback).toHaveBeenCalledTimes((2 ** numberOfDiscs) - 1);\n  });\n\n  it('should solve tower of hanoi puzzle with 6 discs', () => {\n    const moveCallback = jest.fn();\n    const numberOfDiscs = 6;\n\n    hanoiTower({\n      numberOfDiscs,\n      moveCallback,\n    });\n\n    expect(moveCallback).toHaveBeenCalledTimes((2 ** numberOfDiscs) - 1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/hanoi-tower/hanoiTower.js",
    "content": "import Stack from '../../../data-structures/stack/Stack';\n\n/**\n * @param {number} numberOfDiscs\n * @param {Stack} fromPole\n * @param {Stack} withPole\n * @param {Stack} toPole\n * @param {function(disc: number, fromPole: number[], toPole: number[])} moveCallback\n */\nfunction hanoiTowerRecursive({\n  numberOfDiscs,\n  fromPole,\n  withPole,\n  toPole,\n  moveCallback,\n}) {\n  if (numberOfDiscs === 1) {\n    // Base case with just one disc.\n    moveCallback(fromPole.peek(), fromPole.toArray(), toPole.toArray());\n    const disc = fromPole.pop();\n    toPole.push(disc);\n  } else {\n    // In case if there are more discs then move them recursively.\n\n    // Expose the bottom disc on fromPole stack.\n    hanoiTowerRecursive({\n      numberOfDiscs: numberOfDiscs - 1,\n      fromPole,\n      withPole: toPole,\n      toPole: withPole,\n      moveCallback,\n    });\n\n    // Move the disc that was exposed to its final destination.\n    hanoiTowerRecursive({\n      numberOfDiscs: 1,\n      fromPole,\n      withPole,\n      toPole,\n      moveCallback,\n    });\n\n    // Move temporary tower from auxiliary pole to its final destination.\n    hanoiTowerRecursive({\n      numberOfDiscs: numberOfDiscs - 1,\n      fromPole: withPole,\n      withPole: fromPole,\n      toPole,\n      moveCallback,\n    });\n  }\n}\n\n/**\n * @param {number} numberOfDiscs\n * @param {function(disc: number, fromPole: number[], toPole: number[])} moveCallback\n * @param {Stack} [fromPole]\n * @param {Stack} [withPole]\n * @param {Stack} [toPole]\n */\nexport default function hanoiTower({\n  numberOfDiscs,\n  moveCallback,\n  fromPole = new Stack(),\n  withPole = new Stack(),\n  toPole = new Stack(),\n}) {\n  // Each of three poles of Tower of Hanoi puzzle is represented as a stack\n  // that might contain elements (discs). Each disc is represented as a number.\n  // Larger discs have bigger number equivalent.\n\n  // Let's create the discs and put them to the fromPole.\n  for (let discSize = numberOfDiscs; discSize > 0; discSize -= 1) {\n    fromPole.push(discSize);\n  }\n\n  hanoiTowerRecursive({\n    numberOfDiscs,\n    fromPole,\n    withPole,\n    toPole,\n    moveCallback,\n  });\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/README.md",
    "content": "# Jump Game\n\n## The Problem\n\nGiven an array of non-negative integers, you are initially positioned at \nthe first index of the array. Each element in the array represents your maximum \njump length at that position.\n\nDetermine if you are able to reach the last index.\n\n**Example #1**\n\n```\nInput: [2,3,1,1,4]\nOutput: true\nExplanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.\n```\n\n**Example #2**\n\n```\nInput: [3,2,1,0,4]\nOutput: false\nExplanation: You will always arrive at index 3 no matter what. Its maximum\n             jump length is 0, which makes it impossible to reach the last index.\n```\n\n## Naming\n\nWe call a position in the array a **\"good index\"** if starting at that position,\nwe can reach the last index. Otherwise, that index is called a **\"bad index\"**.\nThe problem then reduces to whether or not index 0 is a \"good index\".\n\n## Solutions\n\n### Approach 1: Backtracking\n\nThis is the inefficient solution where we try every single jump pattern that \ntakes us from the first position to the last. We start from the first position \nand jump to every index that is reachable. We repeat the process until last \nindex is reached. When stuck, backtrack.\n\n> See [backtrackingJumpGame.js](backtrackingJumpGame.js) file\n\n**Time complexity:**: `O(2^n)`.\nThere are 2<sup>n</sup> (upper bound) ways of jumping from \nthe first position to the last, where `n` is the length of \narray `nums`.\n\n**Auxiliary Space Complexity**: `O(n)`.\nRecursion requires additional memory for the stack frames.\n\n### Approach 2: Dynamic Programming Top-down\n\nTop-down Dynamic Programming can be thought of as optimized \nbacktracking. It relies on the observation that once we determine \nthat a certain index is good / bad, this result will never change.\nThis means that we can store the result and not need to recompute\nit every time.\n\nTherefore, for each position in the array, we remember whether the \nindex is good or bad. Let's call this array memo and let its values\nbe either one of: GOOD, BAD, UNKNOWN. This technique is \ncalled memoization.\n\n> See [dpTopDownJumpGame.js](dpTopDownJumpGame.js) file\n\n**Time complexity:**: `O(n^2)`.\nFor every element in the array, say `i`, we are looking at the \nnext `nums[i]` elements to its right aiming to find a GOOD\nindex. `nums[i]` can be at most `n`, where `n` is the length \nof array `nums`.\n\n**Auxiliary Space Complexity**: `O(2 * n) = O(n)`.\nFirst `n` originates from recursion. Second `n` comes from the \nusage of the memo table.\n\n### Approach 3: Dynamic Programming Bottom-up\n\nTop-down to bottom-up conversion is done by eliminating recursion. \nIn practice, this achieves better performance as we no longer have the \nmethod stack overhead and might even benefit from some caching. More \nimportantly, this step opens up possibilities for future optimization.\nThe recursion is usually eliminated by trying to reverse the order of \nthe steps from the top-down approach.\n\nThe observation to make here is that we only ever jump to the right.\nThis means that if we start from the right of the array, every time \nwe will query a position to our right, that position has already be\ndetermined as being GOOD or BAD. This means we don't need to recurse\nanymore, as we will always hit the memo table.\n\n> See [dpBottomUpJumpGame.js](dpBottomUpJumpGame.js) file\n\n**Time complexity:**: `O(n^2)`.\nFor every element in the array, say `i`, we are looking at the \nnext `nums[i]` elements to its right aiming to find a GOOD\nindex. `nums[i]` can be at most `n`, where `n` is the length \nof array `nums`.\n\n**Auxiliary Space Complexity**: `O(n)`.\nThis comes from the usage of the memo table.\n \n### Approach 4: Greedy\n\nOnce we have our code in the bottom-up state, we can make one final,\nimportant observation. From a given position, when we try to see if\nwe can jump to a GOOD position, we only ever use one - the first one.\nIn other words, the left-most one. If we keep track of this left-most\nGOOD position as a separate variable, we can avoid searching for it in\nthe array. Not only that, but we can stop using the array altogether.\n\n> See [greedyJumpGame.js](greedyJumpGame.js) file\n\n**Time complexity:**: `O(n)`.\nWe are doing a single pass through the `nums` array, hence `n` steps,\nwhere `n` is the length of array `nums`.\n\n**Auxiliary Space Complexity**: `O(1)`.\nWe are not using any extra memory.\n\n## References\n\n- [Jump Game Fully Explained on LeetCode](https://leetcode.com/articles/jump-game/)\n- [Dynamic Programming vs Divide and Conquer](https://itnext.io/dynamic-programming-vs-divide-and-conquer-2fea680becbe)\n- [Dynamic Programming](https://en.wikipedia.org/wiki/Dynamic_programming)\n- [Memoization on Wikipedia](https://en.wikipedia.org/wiki/Memoization)\n- [Top-Down and Bottom-Up Design on Wikipedia](https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design)\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/__test__/backtrackingJumpGame.test.js",
    "content": "import backtrackingJumpGame from '../backtrackingJumpGame';\n\ndescribe('backtrackingJumpGame', () => {\n  it('should solve Jump Game problem in backtracking manner', () => {\n    expect(backtrackingJumpGame([1, 0])).toBe(true);\n    expect(backtrackingJumpGame([100, 0])).toBe(true);\n    expect(backtrackingJumpGame([2, 3, 1, 1, 4])).toBe(true);\n    expect(backtrackingJumpGame([1, 1, 1, 1, 1])).toBe(true);\n    expect(backtrackingJumpGame([1, 1, 1, 10, 1])).toBe(true);\n    expect(backtrackingJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true);\n\n    expect(backtrackingJumpGame([1, 0, 1])).toBe(false);\n    expect(backtrackingJumpGame([3, 2, 1, 0, 4])).toBe(false);\n    expect(backtrackingJumpGame([0, 0, 0, 0, 0])).toBe(false);\n    expect(backtrackingJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/__test__/dpBottomUpJumpGame.test.js",
    "content": "import dpBottomUpJumpGame from '../dpBottomUpJumpGame';\n\ndescribe('dpBottomUpJumpGame', () => {\n  it('should solve Jump Game problem in bottom-up dynamic programming manner', () => {\n    expect(dpBottomUpJumpGame([1, 0])).toBe(true);\n    expect(dpBottomUpJumpGame([100, 0])).toBe(true);\n    expect(dpBottomUpJumpGame([2, 3, 1, 1, 4])).toBe(true);\n    expect(dpBottomUpJumpGame([1, 1, 1, 1, 1])).toBe(true);\n    expect(dpBottomUpJumpGame([1, 1, 1, 10, 1])).toBe(true);\n    expect(dpBottomUpJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true);\n\n    expect(dpBottomUpJumpGame([1, 0, 1])).toBe(false);\n    expect(dpBottomUpJumpGame([3, 2, 1, 0, 4])).toBe(false);\n    expect(dpBottomUpJumpGame([0, 0, 0, 0, 0])).toBe(false);\n    expect(dpBottomUpJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/__test__/dpTopDownJumpGame.test.js",
    "content": "import dpTopDownJumpGame from '../dpTopDownJumpGame';\n\ndescribe('dpTopDownJumpGame', () => {\n  it('should solve Jump Game problem in top-down dynamic programming manner', () => {\n    expect(dpTopDownJumpGame([1, 0])).toBe(true);\n    expect(dpTopDownJumpGame([100, 0])).toBe(true);\n    expect(dpTopDownJumpGame([2, 3, 1, 1, 4])).toBe(true);\n    expect(dpTopDownJumpGame([1, 1, 1, 1, 1])).toBe(true);\n    expect(dpTopDownJumpGame([1, 1, 1, 10, 1])).toBe(true);\n    expect(dpTopDownJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true);\n\n    expect(dpTopDownJumpGame([1, 0, 1])).toBe(false);\n    expect(dpTopDownJumpGame([3, 2, 1, 0, 4])).toBe(false);\n    expect(dpTopDownJumpGame([0, 0, 0, 0, 0])).toBe(false);\n    expect(dpTopDownJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/__test__/greedyJumpGame.test.js",
    "content": "import greedyJumpGame from '../greedyJumpGame';\n\ndescribe('greedyJumpGame', () => {\n  it('should solve Jump Game problem in greedy manner', () => {\n    expect(greedyJumpGame([1, 0])).toBe(true);\n    expect(greedyJumpGame([100, 0])).toBe(true);\n    expect(greedyJumpGame([2, 3, 1, 1, 4])).toBe(true);\n    expect(greedyJumpGame([1, 1, 1, 1, 1])).toBe(true);\n    expect(greedyJumpGame([1, 1, 1, 10, 1])).toBe(true);\n    expect(greedyJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true);\n\n    expect(greedyJumpGame([1, 0, 1])).toBe(false);\n    expect(greedyJumpGame([3, 2, 1, 0, 4])).toBe(false);\n    expect(greedyJumpGame([0, 0, 0, 0, 0])).toBe(false);\n    expect(greedyJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/backtrackingJumpGame.js",
    "content": "/**\n * BACKTRACKING approach of solving Jump Game.\n *\n * This is the inefficient solution where we try every single jump\n * pattern that takes us from the first position to the last.\n * We start from the first position and jump to every index that\n * is reachable. We repeat the process until last index is reached.\n * When stuck, backtrack.\n *\n * @param {number[]} numbers - array of possible jump length.\n * @param {number} startIndex - index from where we start jumping.\n * @param {number[]} currentJumps - current jumps path.\n * @return {boolean}\n */\nexport default function backtrackingJumpGame(numbers, startIndex = 0, currentJumps = []) {\n  if (startIndex === numbers.length - 1) {\n    // We've jumped directly to last cell. This situation is a solution.\n    return true;\n  }\n\n  // Check what the longest jump we could make from current position.\n  // We don't need to jump beyond the array.\n  const maxJumpLength = Math.min(\n    numbers[startIndex], // Jump is within array.\n    numbers.length - 1 - startIndex, // Jump goes beyond array.\n  );\n\n  // Let's start jumping from startIndex and see whether any\n  // jump is successful and has reached the end of the array.\n  for (let jumpLength = maxJumpLength; jumpLength > 0; jumpLength -= 1) {\n    // Try next jump.\n    const nextIndex = startIndex + jumpLength;\n    currentJumps.push(nextIndex);\n\n    const isJumpSuccessful = backtrackingJumpGame(numbers, nextIndex, currentJumps);\n\n    // Check if current jump was successful.\n    if (isJumpSuccessful) {\n      return true;\n    }\n\n    // BACKTRACKING.\n    // If previous jump wasn't successful then retreat and try the next one.\n    currentJumps.pop();\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/dpBottomUpJumpGame.js",
    "content": "/**\n * DYNAMIC PROGRAMMING BOTTOM-UP approach of solving Jump Game.\n *\n * This comes out as an optimisation of DYNAMIC PROGRAMMING TOP-DOWN approach.\n *\n * The observation to make here is that we only ever jump to the right.\n * This means that if we start from the right of the array, every time we\n * will query a position to our right, that position has already be\n * determined as being GOOD or BAD. This means we don't need to recurse\n * anymore, as we will always hit the memo table.\n *\n * We call a position in the array a \"good\" one if starting at that\n * position, we can reach the last index. Otherwise, that index\n * is called a \"bad\" one.\n *\n * @param {number[]} numbers - array of possible jump length.\n * @return {boolean}\n */\nexport default function dpBottomUpJumpGame(numbers) {\n  // Init cells goodness table.\n  const cellsGoodness = Array(numbers.length).fill(undefined);\n  // Mark the last cell as \"good\" one since it is where we ultimately want to get.\n  cellsGoodness[cellsGoodness.length - 1] = true;\n\n  // Go throw all cells starting from the one before the last\n  // one (since the last one is \"good\" already) and fill cellsGoodness table.\n  for (let cellIndex = numbers.length - 2; cellIndex >= 0; cellIndex -= 1) {\n    const maxJumpLength = Math.min(\n      numbers[cellIndex],\n      numbers.length - 1 - cellIndex,\n    );\n\n    for (let jumpLength = maxJumpLength; jumpLength > 0; jumpLength -= 1) {\n      const nextIndex = cellIndex + jumpLength;\n      if (cellsGoodness[nextIndex] === true) {\n        cellsGoodness[cellIndex] = true;\n        // Once we detected that current cell is good one we don't need to\n        // do further cells checking.\n        break;\n      }\n    }\n  }\n\n  // Now, if the zero's cell is good one then we can jump from it to the end of the array.\n  return cellsGoodness[0] === true;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/dpTopDownJumpGame.js",
    "content": "/**\n * DYNAMIC PROGRAMMING TOP-DOWN approach of solving Jump Game.\n *\n * This comes out as an optimisation of BACKTRACKING approach.\n *\n * It relies on the observation that once we determine that a certain\n * index is good / bad, this result will never change. This means that\n * we can store the result and not need to recompute it every time.\n *\n * We call a position in the array a \"good\" one if starting at that\n * position, we can reach the last index. Otherwise, that index\n * is called a \"bad\" one.\n *\n * @param {number[]} numbers - array of possible jump length.\n * @param {number} startIndex - index from where we start jumping.\n * @param {number[]} currentJumps - current jumps path.\n * @param {boolean[]} cellsGoodness - holds information about whether cell is \"good\" or \"bad\"\n * @return {boolean}\n */\nexport default function dpTopDownJumpGame(\n  numbers,\n  startIndex = 0,\n  currentJumps = [],\n  cellsGoodness = [],\n) {\n  if (startIndex === numbers.length - 1) {\n    // We've jumped directly to last cell. This situation is a solution.\n    return true;\n  }\n\n  // Init cell goodness table if it is empty.\n  // This is DYNAMIC PROGRAMMING feature.\n  const currentCellsGoodness = [...cellsGoodness];\n  if (!currentCellsGoodness.length) {\n    numbers.forEach(() => currentCellsGoodness.push(undefined));\n    // Mark the last cell as \"good\" one since it is where we ultimately want to get.\n    currentCellsGoodness[cellsGoodness.length - 1] = true;\n  }\n\n  // Check what the longest jump we could make from current position.\n  // We don't need to jump beyond the array.\n  const maxJumpLength = Math.min(\n    numbers[startIndex], // Jump is within array.\n    numbers.length - 1 - startIndex, // Jump goes beyond array.\n  );\n\n  // Let's start jumping from startIndex and see whether any\n  // jump is successful and has reached the end of the array.\n  for (let jumpLength = maxJumpLength; jumpLength > 0; jumpLength -= 1) {\n    // Try next jump.\n    const nextIndex = startIndex + jumpLength;\n\n    // Jump only into \"good\" or \"unknown\" cells.\n    // This is top-down dynamic programming optimisation of backtracking algorithm.\n    if (currentCellsGoodness[nextIndex] !== false) {\n      currentJumps.push(nextIndex);\n\n      const isJumpSuccessful = dpTopDownJumpGame(\n        numbers,\n        nextIndex,\n        currentJumps,\n        currentCellsGoodness,\n      );\n\n      // Check if current jump was successful.\n      if (isJumpSuccessful) {\n        return true;\n      }\n\n      // BACKTRACKING.\n      // If previous jump wasn't successful then retreat and try the next one.\n      currentJumps.pop();\n\n      // Mark current cell as \"bad\" to avoid its deep visiting later.\n      currentCellsGoodness[nextIndex] = false;\n    }\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/jump-game/greedyJumpGame.js",
    "content": "/**\n * GREEDY approach of solving Jump Game.\n *\n * This comes out as an optimisation of DYNAMIC PROGRAMMING BOTTOM_UP approach.\n *\n * Once we have our code in the bottom-up state, we can make one final,\n * important observation. From a given position, when we try to see if\n * we can jump to a GOOD position, we only ever use one - the first one.\n * In other words, the left-most one. If we keep track of this left-most\n * GOOD position as a separate variable, we can avoid searching for it\n * in the array. Not only that, but we can stop using the array altogether.\n *\n * We call a position in the array a \"good\" one if starting at that\n * position, we can reach the last index. Otherwise, that index\n * is called a \"bad\" one.\n *\n * @param {number[]} numbers - array of possible jump length.\n * @return {boolean}\n */\nexport default function greedyJumpGame(numbers) {\n  // The \"good\" cell is a cell from which we may jump to the last cell of the numbers array.\n\n  // The last cell in numbers array is for sure the \"good\" one since it is our goal to reach.\n  let leftGoodPosition = numbers.length - 1;\n\n  // Go through all numbers from right to left.\n  for (let numberIndex = numbers.length - 2; numberIndex >= 0; numberIndex -= 1) {\n    // If we can reach the \"good\" cell from the current one then for sure the current\n    // one is also \"good\". Since after all we'll be able to reach the end of the array\n    // from it.\n    const maxCurrentJumpLength = numberIndex + numbers[numberIndex];\n    if (maxCurrentJumpLength >= leftGoodPosition) {\n      leftGoodPosition = numberIndex;\n    }\n  }\n\n  // If the most left \"good\" position is the zero's one then we may say that it IS\n  // possible jump to the end of the array from the first cell;\n  return leftGoodPosition === 0;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/knight-tour/README.md",
    "content": "# Knight's Tour\n\nA **knight's tour** is a sequence of moves of a knight on a chessboard \nsuch that the knight visits every square only once. If the knight \nends on a square that is one knight's move from the beginning \nsquare (so that it could tour the board again immediately, \nfollowing the same path), the tour is **closed**, otherwise it \nis **open**.\n\nThe **knight's tour problem** is the mathematical problem of \nfinding a knight's tour. Creating a program to find a knight's \ntour is a common problem given to computer science students.\nVariations of the knight's tour problem involve chessboards of \ndifferent sizes than the usual `8×8`, as well as irregular \n(non-rectangular) boards.\n\nThe knight's tour problem is an instance of the more \ngeneral **Hamiltonian path problem** in graph theory. The problem of finding \na closed knight's tour is similarly an instance of the Hamiltonian \ncycle problem.\n\n![Knight's Tour](https://upload.wikimedia.org/wikipedia/commons/d/da/Knight%27s_tour_anim_2.gif)\n\nAn open knight's tour of a chessboard.\n\n![Knight's Tour](https://upload.wikimedia.org/wikipedia/commons/c/ca/Knights-Tour-Animation.gif)\n\nAn animation of an open knight's tour on a 5 by 5 board.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Knight%27s_tour)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-1-the-knights-tour-problem/)\n"
  },
  {
    "path": "src/algorithms/uncategorized/knight-tour/__test__/knightTour.test.js",
    "content": "import knightTour from '../knightTour';\n\ndescribe('knightTour', () => {\n  it('should not find solution on 3x3 board', () => {\n    const moves = knightTour(3);\n\n    expect(moves.length).toBe(0);\n  });\n\n  it('should find one solution to do knight tour on 5x5 board', () => {\n    const moves = knightTour(5);\n\n    expect(moves.length).toBe(25);\n\n    expect(moves).toEqual([\n      [0, 0],\n      [1, 2],\n      [2, 0],\n      [0, 1],\n      [1, 3],\n      [3, 4],\n      [2, 2],\n      [4, 1],\n      [3, 3],\n      [1, 4],\n      [0, 2],\n      [1, 0],\n      [3, 1],\n      [4, 3],\n      [2, 4],\n      [0, 3],\n      [1, 1],\n      [3, 0],\n      [4, 2],\n      [2, 1],\n      [4, 0],\n      [3, 2],\n      [4, 4],\n      [2, 3],\n      [0, 4],\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/knight-tour/knightTour.js",
    "content": "/**\n * @param {number[][]} chessboard\n * @param {number[]} position\n * @return {number[][]}\n */\nfunction getPossibleMoves(chessboard, position) {\n  // Generate all knight moves (even those that go beyond the board).\n  const possibleMoves = [\n    [position[0] - 1, position[1] - 2],\n    [position[0] - 2, position[1] - 1],\n    [position[0] + 1, position[1] - 2],\n    [position[0] + 2, position[1] - 1],\n    [position[0] - 2, position[1] + 1],\n    [position[0] - 1, position[1] + 2],\n    [position[0] + 1, position[1] + 2],\n    [position[0] + 2, position[1] + 1],\n  ];\n\n  // Filter out all moves that go beyond the board.\n  return possibleMoves.filter((move) => {\n    const boardSize = chessboard.length;\n    return move[0] >= 0 && move[1] >= 0 && move[0] < boardSize && move[1] < boardSize;\n  });\n}\n\n/**\n * @param {number[][]} chessboard\n * @param {number[]} move\n * @return {boolean}\n */\nfunction isMoveAllowed(chessboard, move) {\n  return chessboard[move[0]][move[1]] !== 1;\n}\n\n/**\n * @param {number[][]} chessboard\n * @param {number[][]} moves\n * @return {boolean}\n */\nfunction isBoardCompletelyVisited(chessboard, moves) {\n  const totalPossibleMovesCount = chessboard.length ** 2;\n  const existingMovesCount = moves.length;\n\n  return totalPossibleMovesCount === existingMovesCount;\n}\n\n/**\n * @param {number[][]} chessboard\n * @param {number[][]} moves\n * @return {boolean}\n */\nfunction knightTourRecursive(chessboard, moves) {\n  const currentChessboard = chessboard;\n\n  // If board has been completely visited then we've found a solution.\n  if (isBoardCompletelyVisited(currentChessboard, moves)) {\n    return true;\n  }\n\n  // Get next possible knight moves.\n  const lastMove = moves[moves.length - 1];\n  const possibleMoves = getPossibleMoves(currentChessboard, lastMove);\n\n  // Try to do next possible moves.\n  for (let moveIndex = 0; moveIndex < possibleMoves.length; moveIndex += 1) {\n    const currentMove = possibleMoves[moveIndex];\n\n    // Check if current move is allowed. We aren't allowed to go to\n    // the same cells twice.\n    if (isMoveAllowed(currentChessboard, currentMove)) {\n      // Actually do the move.\n      moves.push(currentMove);\n      currentChessboard[currentMove[0]][currentMove[1]] = 1;\n\n      // If further moves starting from current are successful then\n      // return true meaning the solution is found.\n      if (knightTourRecursive(currentChessboard, moves)) {\n        return true;\n      }\n\n      // BACKTRACKING.\n      // If current move was unsuccessful then step back and try to do another move.\n      moves.pop();\n      currentChessboard[currentMove[0]][currentMove[1]] = 0;\n    }\n  }\n\n  // Return false if we haven't found solution.\n  return false;\n}\n\n/**\n * @param {number} chessboardSize\n * @return {number[][]}\n */\nexport default function knightTour(chessboardSize) {\n  // Init chessboard.\n  const chessboard = Array(chessboardSize).fill(null).map(() => Array(chessboardSize).fill(0));\n\n  // Init moves array.\n  const moves = [];\n\n  // Do first move and place the knight to the 0x0 cell.\n  const firstMove = [0, 0];\n  moves.push(firstMove);\n  chessboard[firstMove[0]][firstMove[0]] = 1;\n\n  // Recursively try to do the next move.\n  const solutionWasFound = knightTourRecursive(chessboard, moves);\n\n  return solutionWasFound ? moves : [];\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/n-queens/QueenPosition.js",
    "content": "/**\n * Class that represents queen position on the chessboard.\n */\nexport default class QueenPosition {\n  /**\n   * @param {number} rowIndex\n   * @param {number} columnIndex\n   */\n  constructor(rowIndex, columnIndex) {\n    this.rowIndex = rowIndex;\n    this.columnIndex = columnIndex;\n  }\n\n  /**\n   * @return {number}\n   */\n  get leftDiagonal() {\n    // Each position on the same left (\\) diagonal has the same difference of\n    // rowIndex and columnIndex. This fact may be used to quickly check if two\n    // positions (queens) are on the same left diagonal.\n    // @see https://youtu.be/xouin83ebxE?t=1m59s\n    return this.rowIndex - this.columnIndex;\n  }\n\n  /**\n   * @return {number}\n   */\n  get rightDiagonal() {\n    // Each position on the same right diagonal (/) has the same\n    // sum of rowIndex and columnIndex. This fact may be used to quickly\n    // check if two positions (queens) are on the same right diagonal.\n    // @see https://youtu.be/xouin83ebxE?t=1m59s\n    return this.rowIndex + this.columnIndex;\n  }\n\n  toString() {\n    return `${this.rowIndex},${this.columnIndex}`;\n  }\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/n-queens/README.md",
    "content": "# N-Queens Problem\n\nThe **eight queens puzzle** is the problem of placing eight chess queens \non an `8×8` chessboard so that no two queens threaten each other. \nThus, a solution requires that no two queens share the same row, \ncolumn, or diagonal. The eight queens puzzle is an example of the \nmore general *n queens problem* of placing n non-attacking queens \non an `n×n` chessboard, for which solutions exist for all natural \nnumbers `n` with the exception of `n=2` and `n=3`.\n\nFor example, following is a solution for 4 Queen problem.\n\n![N Queens](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/N_Queen_Problem.jpg)\n\nThe expected output is a binary matrix which has 1s for the blocks \nwhere queens are placed. For example following is the output matrix \nfor above 4 queen solution.\n\n```\n{ 0,  1,  0,  0}\n{ 0,  0,  0,  1}\n{ 1,  0,  0,  0}\n{ 0,  0,  1,  0}\n```\n\n## Naive Algorithm\n\nGenerate all possible configurations of queens on board and print a \nconfiguration that satisfies the given constraints.\n\n```\nwhile there are untried configurations\n{\n   generate the next configuration\n   if queens don't attack in this configuration then\n   {\n      print this configuration;\n   }\n}\n```\n\n## Backtracking Algorithm\n\nThe idea is to place queens one by one in different columns, \nstarting from the leftmost column. When we place a queen in a \ncolumn, we check for clashes with already placed queens. In \nthe current column, if we find a row for which there is no \nclash, we mark this row and column as part of the solution. \nIf we do not find such a row due to clashes then we backtrack \nand return false.\n\n```\n1) Start in the leftmost column\n2) If all queens are placed\n    return true\n3) Try all rows in the current column.  Do following for every tried row.\n    a) If the queen can be placed safely in this row then mark this [row, \n        column] as part of the solution and recursively check if placing  \n        queen here leads to a solution.\n    b) If placing queen in [row, column] leads to a solution then return \n        true.\n    c) If placing queen doesn't lead to a solution then unmark this [row, \n        column] (Backtrack) and go to step (a) to try other rows.\n3) If all rows have been tried and nothing worked, return false to trigger \n    backtracking.\n```\n\n## Bitwise Solution\n\nBitwise algorithm basically approaches the problem like this:\n\n- Queens can attack diagonally, vertically, or horizontally. As a result, there \ncan only be one queen in each row, one in each column, and at most one on each \ndiagonal.\n- Since we know there can only one queen per row, we will start at the first row,\nplace a queen, then move to the second row, place a second queen, and so on until\neither a) we reach a valid solution or b) we reach a dead end (ie. we can't place\na queen such that it is \"safe\" from the other queens).\n- Since we are only placing one queen per row, we don't need to worry about\nhorizontal attacks, since no queen will ever be on the same row as another queen.\n- That means we only need to check three things before placing a queen on a\ncertain square: 1) The square's column doesn't have any other queens on it, 2)\nthe square's left diagonal doesn't have any other queens on it, and 3) the\nsquare's right diagonal doesn't have any other queens on it.\n- If we ever reach a point where there is nowhere safe to place a queen, we can\ngive up on our current attempt and immediately test out the next possibility.\n\nFirst let's talk about the recursive function. You'll notice that it accepts \n3 parameters: `leftDiagonal`, `column`, and `rightDiagonal`. Each of these is \ntechnically an integer, but the algorithm takes advantage of the fact that an \ninteger is represented by a sequence of bits. So, think of each of these \nparameters as a sequence of `N` bits.\n\nEach bit in each of the parameters represents whether the corresponding location\non the current row is \"available\".\n\nFor example:\n- For `N=4`, column having a value of `0010` would mean that the 3rd column is \nalready occupied by a queen.\n- For `N=8`, ld having a value of `00011000` at row 5 would mean that the \ntop-left-to-bottom-right diagonals that pass through columns 4 and 5 of that \nrow are already occupied by queens.\n\nBelow is a visual aid for `leftDiagonal`, `column`, and `rightDiagonal`.\n\n![](http://gregtrowbridge.com/content/images/2014/Jul/Screenshot-from-2014-06-17-19-46-20.png)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Eight_queens_puzzle)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-3-n-queen-problem/)\n- [On YouTube by Abdul Bari](https://www.youtube.com/watch?v=xFv_Hl4B83A&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=xouin83ebxE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- Bitwise Solution\n  - [Wikipedia](https://en.wikipedia.org/wiki/Eight_queens_puzzle)\n  - [Solution by Greg Trowbridge](http://gregtrowbridge.com/a-bitwise-solution-to-the-n-queens-problem-in-javascript/)\n  \n"
  },
  {
    "path": "src/algorithms/uncategorized/n-queens/__test__/QueensPosition.test.js",
    "content": "import QueenPosition from '../QueenPosition';\n\ndescribe('QueenPosition', () => {\n  it('should store queen position on chessboard', () => {\n    const position1 = new QueenPosition(0, 0);\n    const position2 = new QueenPosition(2, 1);\n\n    expect(position2.columnIndex).toBe(1);\n    expect(position2.rowIndex).toBe(2);\n    expect(position1.leftDiagonal).toBe(0);\n    expect(position1.rightDiagonal).toBe(0);\n    expect(position2.leftDiagonal).toBe(1);\n    expect(position2.rightDiagonal).toBe(3);\n    expect(position2.toString()).toBe('2,1');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/n-queens/__test__/nQueens.test.js",
    "content": "import nQueens from '../nQueens';\n\ndescribe('nQueens', () => {\n  it('should not hae solution for 3 queens', () => {\n    const solutions = nQueens(3);\n    expect(solutions.length).toBe(0);\n  });\n\n  it('should solve n-queens problem for 4 queens', () => {\n    const solutions = nQueens(4);\n    expect(solutions.length).toBe(2);\n\n    // First solution.\n    expect(solutions[0][0].toString()).toBe('0,1');\n    expect(solutions[0][1].toString()).toBe('1,3');\n    expect(solutions[0][2].toString()).toBe('2,0');\n    expect(solutions[0][3].toString()).toBe('3,2');\n\n    // Second solution (mirrored).\n    expect(solutions[1][0].toString()).toBe('0,2');\n    expect(solutions[1][1].toString()).toBe('1,0');\n    expect(solutions[1][2].toString()).toBe('2,3');\n    expect(solutions[1][3].toString()).toBe('3,1');\n  });\n\n  it('should solve n-queens problem for 6 queens', () => {\n    const solutions = nQueens(6);\n    expect(solutions.length).toBe(4);\n\n    // First solution.\n    expect(solutions[0][0].toString()).toBe('0,1');\n    expect(solutions[0][1].toString()).toBe('1,3');\n    expect(solutions[0][2].toString()).toBe('2,5');\n    expect(solutions[0][3].toString()).toBe('3,0');\n    expect(solutions[0][4].toString()).toBe('4,2');\n    expect(solutions[0][5].toString()).toBe('5,4');\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/n-queens/__test__/nQueensBitwise.test.js",
    "content": "import nQueensBitwise from '../nQueensBitwise';\n\ndescribe('nQueensBitwise', () => {\n  it('should have solutions for 4 to N queens', () => {\n    expect(nQueensBitwise(4)).toBe(2);\n    expect(nQueensBitwise(5)).toBe(10);\n    expect(nQueensBitwise(6)).toBe(4);\n    expect(nQueensBitwise(7)).toBe(40);\n    expect(nQueensBitwise(8)).toBe(92);\n    expect(nQueensBitwise(9)).toBe(352);\n    expect(nQueensBitwise(10)).toBe(724);\n    expect(nQueensBitwise(11)).toBe(2680);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/n-queens/nQueens.js",
    "content": "import QueenPosition from './QueenPosition';\n\n/**\n * @param {QueenPosition[]} queensPositions\n * @param {number} rowIndex\n * @param {number} columnIndex\n * @return {boolean}\n */\nfunction isSafe(queensPositions, rowIndex, columnIndex) {\n  // New position to which the Queen is going to be placed.\n  const newQueenPosition = new QueenPosition(rowIndex, columnIndex);\n\n  // Check if new queen position conflicts with any other queens.\n  for (let queenIndex = 0; queenIndex < queensPositions.length; queenIndex += 1) {\n    const currentQueenPosition = queensPositions[queenIndex];\n\n    if (\n      // Check if queen has been already placed.\n      currentQueenPosition\n      && (\n        // Check if there are any queen on the same column.\n        newQueenPosition.columnIndex === currentQueenPosition.columnIndex\n        // Check if there are any queen on the same row.\n        || newQueenPosition.rowIndex === currentQueenPosition.rowIndex\n        // Check if there are any queen on the same left diagonal.\n        || newQueenPosition.leftDiagonal === currentQueenPosition.leftDiagonal\n        // Check if there are any queen on the same right diagonal.\n        || newQueenPosition.rightDiagonal === currentQueenPosition.rightDiagonal\n      )\n    ) {\n      // Can't place queen into current position since there are other queens that\n      // are threatening it.\n      return false;\n    }\n  }\n\n  // Looks like we're safe.\n  return true;\n}\n\n/**\n * @param {QueenPosition[][]} solutions\n * @param {QueenPosition[]} previousQueensPositions\n * @param {number} queensCount\n * @param {number} rowIndex\n * @return {boolean}\n */\nfunction nQueensRecursive(solutions, previousQueensPositions, queensCount, rowIndex) {\n  // Clone positions array.\n  const queensPositions = [...previousQueensPositions].map((queenPosition) => {\n    return !queenPosition ? queenPosition : new QueenPosition(\n      queenPosition.rowIndex,\n      queenPosition.columnIndex,\n    );\n  });\n\n  if (rowIndex === queensCount) {\n    // We've successfully reached the end of the board.\n    // Store solution to the list of solutions.\n    solutions.push(queensPositions);\n\n    // Solution found.\n    return true;\n  }\n\n  // Let's try to put queen at row rowIndex into its safe column position.\n  for (let columnIndex = 0; columnIndex < queensCount; columnIndex += 1) {\n    if (isSafe(queensPositions, rowIndex, columnIndex)) {\n      // Place current queen to its current position.\n      queensPositions[rowIndex] = new QueenPosition(rowIndex, columnIndex);\n\n      // Try to place all other queens as well.\n      nQueensRecursive(solutions, queensPositions, queensCount, rowIndex + 1);\n\n      // BACKTRACKING.\n      // Remove the queen from the row to avoid isSafe() returning false.\n      queensPositions[rowIndex] = null;\n    }\n  }\n\n  return false;\n}\n\n/**\n * @param {number} queensCount\n * @return {QueenPosition[][]}\n */\nexport default function nQueens(queensCount) {\n  // Init NxN chessboard with zeros.\n  // const chessboard = Array(queensCount).fill(null).map(() => Array(queensCount).fill(0));\n\n  // This array will hold positions or coordinates of each of\n  // N queens in form of [rowIndex, columnIndex].\n  const queensPositions = Array(queensCount).fill(null);\n\n  /** @var {QueenPosition[][]} solutions */\n  const solutions = [];\n\n  // Solve problem recursively.\n  nQueensRecursive(solutions, queensPositions, queensCount, 0);\n\n  return solutions;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/n-queens/nQueensBitwise.js",
    "content": "/**\n * Checks all possible board configurations.\n *\n * @param {number} boardSize - Size of the squared chess board.\n * @param {number} leftDiagonal - Sequence of N bits that show whether the corresponding location\n * on the current row is \"available\" (no other queens are threatening from left diagonal).\n * @param {number} column - Sequence of N bits that show whether the corresponding location\n * on the current row is \"available\" (no other queens are threatening from columns).\n * @param {number} rightDiagonal - Sequence of N bits that show whether the corresponding location\n * on the current row is \"available\" (no other queens are threatening from right diagonal).\n * @param {number} solutionsCount - Keeps track of the number of valid solutions.\n * @return {number} - Number of possible solutions.\n */\nfunction nQueensBitwiseRecursive(\n  boardSize,\n  leftDiagonal = 0,\n  column = 0,\n  rightDiagonal = 0,\n  solutionsCount = 0,\n) {\n  // Keeps track of the number of valid solutions.\n  let currentSolutionsCount = solutionsCount;\n\n  // Helps to identify valid solutions.\n  // isDone simply has a bit sequence with 1 for every entry up to the Nth. For example,\n  // when N=5, done will equal 11111. The \"isDone\" variable simply allows us to not worry about any\n  // bits beyond the Nth.\n  const isDone = (2 ** boardSize) - 1;\n\n  // All columns are occupied (i.e. 0b1111 for boardSize = 4), so the solution must be complete.\n  // Since the algorithm never places a queen illegally (ie. when it can attack or be attacked),\n  // we know that if all the columns have been filled, we must have a valid solution.\n  if (column === isDone) {\n    return currentSolutionsCount + 1;\n  }\n\n  // Gets a bit sequence with \"1\"s wherever there is an open \"slot\".\n  // All that's happening here is we're taking col, ld, and rd, and if any of the columns are\n  // \"under attack\", we mark that column as 0 in poss, basically meaning \"we can't put a queen in\n  // this column\". Thus all bits position in poss that are '1's are available for placing\n  // queen there.\n  let availablePositions = ~(leftDiagonal | rightDiagonal | column);\n\n  // Loops as long as there is a valid place to put another queen.\n  // For N=4 the isDone=0b1111. Then if availablePositions=0b0000 (which would mean that all places\n  // are under threatening) we must stop trying to place a queen.\n  while (availablePositions & isDone) {\n    // firstAvailablePosition just stores the first non-zero bit (ie. the first available location).\n    // So if firstAvailablePosition was 0010, it would mean the 3rd column of the current row.\n    // And that would be the position will be placing our next queen.\n    //\n    // For example:\n    // availablePositions = 0b01100\n    // firstAvailablePosition = 100\n    const firstAvailablePosition = availablePositions & -availablePositions;\n\n    // This line just marks that position in the current row as being \"taken\" by flipping that\n    // column in availablePositions to zero. This way, when the while loop continues, we'll know\n    // not to try that location again.\n    //\n    // For example:\n    // availablePositions = 0b0100\n    // firstAvailablePosition = 0b10\n    // 0b0110 - 0b10 = 0b0100\n    availablePositions -= firstAvailablePosition;\n\n    /*\n     * The operators >> 1 and 1 << simply move all the bits in a bit sequence one digit to the\n     * right or left, respectively. So calling (rd|bit)<<1 simply says: combine rd and bit with\n     * an OR operation, then move everything in the result to the left by one digit.\n     *\n     * More specifically, if rd is 0001 (meaning that the top-right-to-bottom-left diagonal through\n     * column 4 of the current row is occupied), and bit is 0100 (meaning that we are planning to\n     * place a queen in column 2 of the current row), (rd|bit) results in 0101 (meaning that after\n     * we place a queen in column 2 of the current row, the second and the fourth\n     * top-right-to-bottom-left diagonals will be occupied).\n     *\n     * Now, if add in the << operator, we get (rd|bit)<<1, which takes the 0101 we worked out in\n     * our previous bullet point, and moves everything to the left by one. The result, therefore,\n     * is 1010.\n     */\n    currentSolutionsCount += nQueensBitwiseRecursive(\n      boardSize,\n      (leftDiagonal | firstAvailablePosition) >> 1,\n      column | firstAvailablePosition,\n      (rightDiagonal | firstAvailablePosition) << 1,\n      solutionsCount,\n    );\n  }\n\n  return currentSolutionsCount;\n}\n\n/**\n * @param {number} boardSize - Size of the squared chess board.\n * @return {number} - Number of possible solutions.\n * @see http://gregtrowbridge.com/a-bitwise-solution-to-the-n-queens-problem-in-javascript/\n */\nexport default function nQueensBitwise(boardSize) {\n  return nQueensBitwiseRecursive(boardSize);\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/rain-terraces/README.md",
    "content": "# Rain Terraces (Trapping Rain Water) Problem\n\nGiven an array of non-negative integers representing terraces in an elevation map \nwhere the width of each bar is `1`, compute how much water it is able to trap \nafter raining.\n\n![Rain Terraces](https://www.geeksforgeeks.org/wp-content/uploads/watertrap.png)\n\n## Examples\n\n**Example #1**\n\n```\nInput: arr[] = [2, 0, 2]\nOutput: 2\nStructure is like below:\n\n| |\n|_|\n\nWe can trap 2 units of water in the middle gap.\n```\n\n**Example #2**\n\n```\nInput: arr[] = [3, 0, 0, 2, 0, 4]\nOutput: 10\nStructure is like below:\n\n     |\n|    |\n|  | |\n|__|_| \n\nWe can trap \"3*2 units\" of water between 3 an 2,\n\"1 unit\" on top of bar 2 and \"3 units\" between 2 \nand 4. See below diagram also.\n```\n\n**Example #3**\n\n```\nInput: arr[] = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]\nOutput: 6\nStructure is like below:\n\n       | \n   |   || |\n_|_||_||||||\n\nTrap \"1 unit\" between first 1 and 2, \"4 units\" between\nfirst 2 and 3 and \"1 unit\" between second last 1 and last 2.\n```\n\n## The Algorithm\n\nAn element of array can store water if there are higher bars on left and right. \nWe can find amount of water to be stored in every element by finding the heights \nof bars on left and right sides. The idea is to compute amount of water that can\nbe stored in every element of array. For example, consider the array\n`[3, 0, 0, 2, 0, 4]`, We can trap \"3*2 units\" of water between 3 an 2, \"1 unit\" \non top of bar 2 and \"3 units\" between 2 and 4. See below diagram also.\n\n### Approach 1: Brute force\n\n**Intuition**\n\nFor each element in the array, we find the maximum level of water it can trap \nafter the rain, which is equal to the minimum of maximum height of bars on both \nthe sides minus its own height.\n\n**Steps**\n\n- Initialize `answer = 0`\n- Iterate the array from left to right:\n  - Initialize `max_left = 0`  and `max_right = 0`\n  - Iterate from the current element to the beginning of array updating: `max_left = max(max_left, height[j])`\n  - Iterate from the current element to the end of array updating: `max_right = max(max_right, height[j])`\n  - Add `min(max_left, max_right) − height[i]` to `answer`\n\n**Complexity Analysis**\n\nTime complexity: `O(n^2)`. For each element of array, we iterate the left and right parts.\n\nAuxiliary space complexity: `O(1)` extra space.\n\n### Approach 2: Dynamic Programming\n\n**Intuition**\n\nIn brute force, we iterate over the left and right parts again and again just to \nfind the highest bar size up to that index. But, this could be stored. Voila, \ndynamic programming.\n\nSo we may pre-compute highest bar on left and right of every bar in `O(n)` time.\nThen use these pre-computed values to find the amount of water in every array element.\n\nThe concept is illustrated as shown:\n\n![DP Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/Figures/42/trapping_rain_water.png)\n\n**Steps**\n\n- Find maximum height of bar from the left end up to an index `i` in the array `left_max`.\n- Find maximum height of bar from the right end up to an index `i` in the array `right_max`.\n- Iterate over the `height` array and update `answer`:\n  - Add `min(max_left[i], max_right[i]) − height[i]` to `answer`.\n\n**Complexity Analysis**\n\nTime complexity: `O(n)`. We store the maximum heights upto a point using 2 \niterations of `O(n)` each. We finally update `answer` using the stored \nvalues in `O(n)`.\n\nAuxiliary space complexity: `O(n)` extra space. Additional space \nfor `left_max` and `right_max` arrays than in Approach 1.\n\n## References\n\n- [GeeksForGeeks](https://www.geeksforgeeks.org/trapping-rain-water/)\n- [LeetCode](https://leetcode.com/problems/trapping-rain-water/solution/)\n"
  },
  {
    "path": "src/algorithms/uncategorized/rain-terraces/__test__/bfRainTerraces.test.js",
    "content": "import bfRainTerraces from '../bfRainTerraces';\n\ndescribe('bfRainTerraces', () => {\n  it('should find the amount of water collected after raining', () => {\n    expect(bfRainTerraces([1])).toBe(0);\n    expect(bfRainTerraces([1, 0])).toBe(0);\n    expect(bfRainTerraces([0, 1])).toBe(0);\n    expect(bfRainTerraces([0, 1, 0])).toBe(0);\n    expect(bfRainTerraces([0, 1, 0, 0])).toBe(0);\n    expect(bfRainTerraces([0, 1, 0, 0, 1, 0])).toBe(2);\n    expect(bfRainTerraces([0, 2, 0, 0, 1, 0])).toBe(2);\n    expect(bfRainTerraces([2, 0, 2])).toBe(2);\n    expect(bfRainTerraces([2, 0, 5])).toBe(2);\n    expect(bfRainTerraces([3, 0, 0, 2, 0, 4])).toBe(10);\n    expect(bfRainTerraces([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toBe(6);\n    expect(bfRainTerraces([1, 1, 1, 1, 1])).toBe(0);\n    expect(bfRainTerraces([1, 2, 3, 4, 5])).toBe(0);\n    expect(bfRainTerraces([4, 1, 3, 1, 2, 1, 2, 1])).toBe(4);\n    expect(bfRainTerraces([0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0])).toBe(7);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/rain-terraces/__test__/dpRainTerraces.test.js",
    "content": "import dpRainTerraces from '../dpRainTerraces';\n\ndescribe('dpRainTerraces', () => {\n  it('should find the amount of water collected after raining', () => {\n    expect(dpRainTerraces([1])).toBe(0);\n    expect(dpRainTerraces([1, 0])).toBe(0);\n    expect(dpRainTerraces([0, 1])).toBe(0);\n    expect(dpRainTerraces([0, 1, 0])).toBe(0);\n    expect(dpRainTerraces([0, 1, 0, 0])).toBe(0);\n    expect(dpRainTerraces([0, 1, 0, 0, 1, 0])).toBe(2);\n    expect(dpRainTerraces([0, 2, 0, 0, 1, 0])).toBe(2);\n    expect(dpRainTerraces([2, 0, 2])).toBe(2);\n    expect(dpRainTerraces([2, 0, 5])).toBe(2);\n    expect(dpRainTerraces([3, 0, 0, 2, 0, 4])).toBe(10);\n    expect(dpRainTerraces([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toBe(6);\n    expect(dpRainTerraces([1, 1, 1, 1, 1])).toBe(0);\n    expect(dpRainTerraces([1, 2, 3, 4, 5])).toBe(0);\n    expect(dpRainTerraces([4, 1, 3, 1, 2, 1, 2, 1])).toBe(4);\n    expect(dpRainTerraces([0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0])).toBe(7);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/rain-terraces/bfRainTerraces.js",
    "content": "/**\n * BRUTE FORCE approach of solving Trapping Rain Water problem.\n *\n * @param {number[]} terraces\n * @return {number}\n */\nexport default function bfRainTerraces(terraces) {\n  let waterAmount = 0;\n\n  for (let terraceIndex = 0; terraceIndex < terraces.length; terraceIndex += 1) {\n    // Get left most high terrace.\n    let leftHighestLevel = 0;\n    for (let leftIndex = terraceIndex - 1; leftIndex >= 0; leftIndex -= 1) {\n      leftHighestLevel = Math.max(leftHighestLevel, terraces[leftIndex]);\n    }\n\n    // Get right most high terrace.\n    let rightHighestLevel = 0;\n    for (let rightIndex = terraceIndex + 1; rightIndex < terraces.length; rightIndex += 1) {\n      rightHighestLevel = Math.max(rightHighestLevel, terraces[rightIndex]);\n    }\n\n    // Add current terrace water amount.\n    const terraceBoundaryLevel = Math.min(leftHighestLevel, rightHighestLevel);\n    if (terraceBoundaryLevel > terraces[terraceIndex]) {\n      // Terrace will be able to store the water if the lowest of two left and right highest\n      // terraces are still higher than the current one.\n      waterAmount += terraceBoundaryLevel - terraces[terraceIndex];\n    }\n  }\n\n  return waterAmount;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/rain-terraces/dpRainTerraces.js",
    "content": "/**\n * DYNAMIC PROGRAMMING approach of solving Trapping Rain Water problem.\n *\n * @param {number[]} terraces\n * @return {number}\n */\nexport default function dpRainTerraces(terraces) {\n  let waterAmount = 0;\n\n  // Init arrays that will keep the list of left and right maximum levels for specific positions.\n  const leftMaxLevels = new Array(terraces.length).fill(0);\n  const rightMaxLevels = new Array(terraces.length).fill(0);\n\n  // Calculate the highest terrace level from the LEFT relative to the current terrace.\n  [leftMaxLevels[0]] = terraces;\n  for (let terraceIndex = 1; terraceIndex < terraces.length; terraceIndex += 1) {\n    leftMaxLevels[terraceIndex] = Math.max(\n      terraces[terraceIndex],\n      leftMaxLevels[terraceIndex - 1],\n    );\n  }\n\n  // Calculate the highest terrace level from the RIGHT relative to the current terrace.\n  rightMaxLevels[terraces.length - 1] = terraces[terraces.length - 1];\n  for (let terraceIndex = terraces.length - 2; terraceIndex >= 0; terraceIndex -= 1) {\n    rightMaxLevels[terraceIndex] = Math.max(\n      terraces[terraceIndex],\n      rightMaxLevels[terraceIndex + 1],\n    );\n  }\n\n  // Not let's go through all terraces one by one and calculate how much water\n  // each terrace may accumulate based on previously calculated values.\n  for (let terraceIndex = 0; terraceIndex < terraces.length; terraceIndex += 1) {\n    // Pick the lowest from the left/right highest terraces.\n    const currentTerraceBoundary = Math.min(\n      leftMaxLevels[terraceIndex],\n      rightMaxLevels[terraceIndex],\n    );\n\n    if (currentTerraceBoundary > terraces[terraceIndex]) {\n      waterAmount += currentTerraceBoundary - terraces[terraceIndex];\n    }\n  }\n\n  return waterAmount;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/README.md",
    "content": "# Recursive Staircase Problem\n\n## The Problem\n\nThere 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._\n\n![](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/nth-stair.png)\n\n## The Solution\n\nThis is an interesting problem because there are several ways of how it may be solved that illustrate different programming paradigms.\n\n- [Brute Force Recursive Solution](./recursiveStaircaseBF.js) - Time: `O(2^n)`; Space: `O(1)`\n- [Recursive Solution With Memoization](./recursiveStaircaseMEM.js) - Time: `O(n)`; Space: `O(n)`\n- [Dynamic Programming Solution](./recursiveStaircaseDP.js) - Time: `O(n)`; Space: `O(n)`\n- [Iterative Solution](./recursiveStaircaseIT.js) - Time: `O(n)`; Space: `O(1)` \n\n## References\n\n- [On YouTube by Gayle Laakmann McDowell](https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/count-ways-reach-nth-stair/)\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseBF.test.js",
    "content": "import recursiveStaircaseBF from '../recursiveStaircaseBF';\n\ndescribe('recursiveStaircaseBF', () => {\n  it('should calculate number of variants using Brute Force solution', () => {\n    expect(recursiveStaircaseBF(-1)).toBe(0);\n    expect(recursiveStaircaseBF(0)).toBe(0);\n    expect(recursiveStaircaseBF(1)).toBe(1);\n    expect(recursiveStaircaseBF(2)).toBe(2);\n    expect(recursiveStaircaseBF(3)).toBe(3);\n    expect(recursiveStaircaseBF(4)).toBe(5);\n    expect(recursiveStaircaseBF(5)).toBe(8);\n    expect(recursiveStaircaseBF(6)).toBe(13);\n    expect(recursiveStaircaseBF(7)).toBe(21);\n    expect(recursiveStaircaseBF(8)).toBe(34);\n    expect(recursiveStaircaseBF(9)).toBe(55);\n    expect(recursiveStaircaseBF(10)).toBe(89);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseDP.test.js",
    "content": "import recursiveStaircaseDP from '../recursiveStaircaseDP';\n\ndescribe('recursiveStaircaseDP', () => {\n  it('should calculate number of variants using Dynamic Programming solution', () => {\n    expect(recursiveStaircaseDP(-1)).toBe(0);\n    expect(recursiveStaircaseDP(0)).toBe(0);\n    expect(recursiveStaircaseDP(1)).toBe(1);\n    expect(recursiveStaircaseDP(2)).toBe(2);\n    expect(recursiveStaircaseDP(3)).toBe(3);\n    expect(recursiveStaircaseDP(4)).toBe(5);\n    expect(recursiveStaircaseDP(5)).toBe(8);\n    expect(recursiveStaircaseDP(6)).toBe(13);\n    expect(recursiveStaircaseDP(7)).toBe(21);\n    expect(recursiveStaircaseDP(8)).toBe(34);\n    expect(recursiveStaircaseDP(9)).toBe(55);\n    expect(recursiveStaircaseDP(10)).toBe(89);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseIT.test.js",
    "content": "import recursiveStaircaseIT from '../recursiveStaircaseIT';\n\ndescribe('recursiveStaircaseIT', () => {\n  it('should calculate number of variants using Iterative solution', () => {\n    expect(recursiveStaircaseIT(-1)).toBe(0);\n    expect(recursiveStaircaseIT(0)).toBe(0);\n    expect(recursiveStaircaseIT(1)).toBe(1);\n    expect(recursiveStaircaseIT(2)).toBe(2);\n    expect(recursiveStaircaseIT(3)).toBe(3);\n    expect(recursiveStaircaseIT(4)).toBe(5);\n    expect(recursiveStaircaseIT(5)).toBe(8);\n    expect(recursiveStaircaseIT(6)).toBe(13);\n    expect(recursiveStaircaseIT(7)).toBe(21);\n    expect(recursiveStaircaseIT(8)).toBe(34);\n    expect(recursiveStaircaseIT(9)).toBe(55);\n    expect(recursiveStaircaseIT(10)).toBe(89);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseMEM.test.js",
    "content": "import recursiveStaircaseMEM from '../recursiveStaircaseMEM';\n\ndescribe('recursiveStaircaseMEM', () => {\n  it('should calculate number of variants using Brute Force with Memoization', () => {\n    expect(recursiveStaircaseMEM(-1)).toBe(0);\n    expect(recursiveStaircaseMEM(0)).toBe(0);\n    expect(recursiveStaircaseMEM(1)).toBe(1);\n    expect(recursiveStaircaseMEM(2)).toBe(2);\n    expect(recursiveStaircaseMEM(3)).toBe(3);\n    expect(recursiveStaircaseMEM(4)).toBe(5);\n    expect(recursiveStaircaseMEM(5)).toBe(8);\n    expect(recursiveStaircaseMEM(6)).toBe(13);\n    expect(recursiveStaircaseMEM(7)).toBe(21);\n    expect(recursiveStaircaseMEM(8)).toBe(34);\n    expect(recursiveStaircaseMEM(9)).toBe(55);\n    expect(recursiveStaircaseMEM(10)).toBe(89);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/recursiveStaircaseBF.js",
    "content": "/**\n * Recursive Staircase Problem (Brute Force Solution).\n *\n * @param {number} stairsNum - Number of stairs to climb on.\n * @return {number} - Number of ways to climb a staircase.\n */\nexport default function recursiveStaircaseBF(stairsNum) {\n  if (stairsNum <= 0) {\n    // There is no way to go down - you climb the stairs only upwards.\n    // Also if you're standing on the ground floor that you don't need to do any further steps.\n    return 0;\n  }\n\n  if (stairsNum === 1) {\n    // There is only one way to go to the first step.\n    return 1;\n  }\n\n  if (stairsNum === 2) {\n    // There are two ways to get to the second steps: (1 + 1) or (2).\n    return 2;\n  }\n\n  // Sum up how many steps we need to take after doing one step up with the number of\n  // steps we need to take after doing two steps up.\n  return recursiveStaircaseBF(stairsNum - 1) + recursiveStaircaseBF(stairsNum - 2);\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/recursiveStaircaseDP.js",
    "content": "/**\n * Recursive Staircase Problem (Dynamic Programming Solution).\n *\n * @param {number} stairsNum - Number of stairs to climb on.\n * @return {number} - Number of ways to climb a staircase.\n */\nexport default function recursiveStaircaseDP(stairsNum) {\n  if (stairsNum < 0) {\n    // There is no way to go down - you climb the stairs only upwards.\n    return 0;\n  }\n\n  // Init the steps vector that will hold all possible ways to get to the corresponding step.\n  const steps = new Array(stairsNum + 1).fill(0);\n\n  // Init the number of ways to get to the 0th, 1st and 2nd steps.\n  steps[0] = 0;\n  steps[1] = 1;\n  steps[2] = 2;\n\n  if (stairsNum <= 2) {\n    // Return the number of ways to get to the 0th or 1st or 2nd steps.\n    return steps[stairsNum];\n  }\n\n  // Calculate every next step based on two previous ones.\n  for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) {\n    steps[currentStep] = steps[currentStep - 1] + steps[currentStep - 2];\n  }\n\n  // Return possible ways to get to the requested step.\n  return steps[stairsNum];\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/recursiveStaircaseIT.js",
    "content": "/**\n * Recursive Staircase Problem (Iterative Solution).\n *\n * @param {number} stairsNum - Number of stairs to climb on.\n * @return {number} - Number of ways to climb a staircase.\n */\nexport default function recursiveStaircaseIT(stairsNum) {\n  if (stairsNum <= 0) {\n    // There is no way to go down - you climb the stairs only upwards.\n    // Also you don't need to do anything to stay on the 0th step.\n    return 0;\n  }\n\n  // Init the number of ways to get to the 0th, 1st and 2nd steps.\n  const steps = [1, 2];\n\n  if (stairsNum <= 2) {\n    // Return the number of possible ways of how to get to the 1st or 2nd steps.\n    return steps[stairsNum - 1];\n  }\n\n  // Calculate the number of ways to get to the n'th step based on previous ones.\n  // Comparing to Dynamic Programming solution we don't store info for all the steps but\n  // rather for two previous ones only.\n  for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) {\n    [steps[0], steps[1]] = [steps[1], steps[0] + steps[1]];\n  }\n\n  // Return possible ways to get to the requested step.\n  return steps[1];\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/recursive-staircase/recursiveStaircaseMEM.js",
    "content": "/**\n * Recursive Staircase Problem (Recursive Solution With Memoization).\n *\n * @param {number} totalStairs - Number of stairs to climb on.\n * @return {number} - Number of ways to climb a staircase.\n */\nexport default function recursiveStaircaseMEM(totalStairs) {\n  // Memo table that will hold all recursively calculated results to avoid calculating them\n  // over and over again.\n  const memo = [];\n\n  // Recursive closure.\n  const getSteps = (stairsNum) => {\n    if (stairsNum <= 0) {\n      // There is no way to go down - you climb the stairs only upwards.\n      // Also if you're standing on the ground floor that you don't need to do any further steps.\n      return 0;\n    }\n\n    if (stairsNum === 1) {\n      // There is only one way to go to the first step.\n      return 1;\n    }\n\n    if (stairsNum === 2) {\n      // There are two ways to get to the second steps: (1 + 1) or (2).\n      return 2;\n    }\n\n    // Avoid recursion for the steps that we've calculated recently.\n    if (memo[stairsNum]) {\n      return memo[stairsNum];\n    }\n\n    // Sum up how many steps we need to take after doing one step up with the number of\n    // steps we need to take after doing two steps up.\n    memo[stairsNum] = getSteps(stairsNum - 1) + getSteps(stairsNum - 2);\n\n    return memo[stairsNum];\n  };\n\n  // Return possible ways to get to the requested step.\n  return getSteps(totalStairs);\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/square-matrix-rotation/README.md",
    "content": "# Square Matrix In-Place Rotation\n\n## The Problem\n\nYou are given an `n x n` 2D matrix (representing an image). \nRotate the matrix by `90` degrees (clockwise).\n\n**Note**\n\nYou have to rotate the image **in-place**, which means you \nhave to modify the input 2D matrix directly. **DO NOT** allocate\nanother 2D matrix and do the rotation.\n\n## Examples\n\n**Example #1**\n\nGiven input matrix:\n\n```\n[\n  [1, 2, 3],\n  [4, 5, 6],\n  [7, 8, 9],\n]\n```\n\nRotate the input matrix in-place such that it becomes:\n\n```\n[\n  [7, 4, 1],\n  [8, 5, 2],\n  [9, 6, 3],\n]\n```\n\n**Example #2**\n\nGiven input matrix:\n\n```\n[\n  [5, 1, 9, 11],\n  [2, 4, 8, 10],\n  [13, 3, 6, 7],\n  [15, 14, 12, 16],\n]\n```\n\nRotate the input matrix in-place such that it becomes:\n\n```\n[\n  [15, 13, 2, 5],\n  [14, 3, 4, 1],\n  [12, 6, 8, 9],\n  [16, 7, 10, 11],\n]\n```\n\n## Algorithm\n\nWe would need to do two reflections of the matrix: \n\n- reflect vertically\n- reflect diagonally from bottom-left to top-right\n\nOr we also could Furthermore, you can reflect diagonally \ntop-left/bottom-right and reflect horizontally.\n\nA common question is how do you even figure out what kind \nof reflections to do? Simply rip a square piece of paper,\nwrite a random word on it so you know its rotation. Then,\nflip the square piece of paper around until you figure out\nhow to come to the solution.\n \nHere is an example of how first line may be rotated using\ndiagonal top-right/bottom-left rotation along with horizontal\nrotation.\n\n```\nLet's say we have a string at the top of the matrix:\n\nA B C\n• • •\n• • •\n\nLet's do top-right/bottom-left diagonal reflection:\n\nA B C\n/ / •\n/ • •  \n\nAnd now let's do horizontal reflection:\n\nA → →\nB → →\nC → →\n\nThe string has been rotated to 90 degree:\n\n• • A\n• • B\n• • C\n```\n\n## References\n\n- [LeetCode](https://leetcode.com/problems/rotate-image/description/)\n"
  },
  {
    "path": "src/algorithms/uncategorized/square-matrix-rotation/__test__/squareMatrixRotation.test.js",
    "content": "import squareMatrixRotation from '../squareMatrixRotation';\n\ndescribe('squareMatrixRotation', () => {\n  it('should rotate matrix #0 in-place', () => {\n    const matrix = [[1]];\n\n    const rotatedMatrix = [[1]];\n\n    expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix);\n  });\n\n  it('should rotate matrix #1 in-place', () => {\n    const matrix = [\n      [1, 2],\n      [3, 4],\n    ];\n\n    const rotatedMatrix = [\n      [3, 1],\n      [4, 2],\n    ];\n\n    expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix);\n  });\n\n  it('should rotate matrix #2 in-place', () => {\n    const matrix = [\n      [1, 2, 3],\n      [4, 5, 6],\n      [7, 8, 9],\n    ];\n\n    const rotatedMatrix = [\n      [7, 4, 1],\n      [8, 5, 2],\n      [9, 6, 3],\n    ];\n\n    expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix);\n  });\n\n  it('should rotate matrix #3 in-place', () => {\n    const matrix = [\n      [5, 1, 9, 11],\n      [2, 4, 8, 10],\n      [13, 3, 6, 7],\n      [15, 14, 12, 16],\n    ];\n\n    const rotatedMatrix = [\n      [15, 13, 2, 5],\n      [14, 3, 4, 1],\n      [12, 6, 8, 9],\n      [16, 7, 10, 11],\n    ];\n\n    expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/square-matrix-rotation/squareMatrixRotation.js",
    "content": "/**\n * @param {*[][]} originalMatrix\n * @return {*[][]}\n */\nexport default function squareMatrixRotation(originalMatrix) {\n  const matrix = originalMatrix.slice();\n\n  // Do top-right/bottom-left diagonal reflection of the matrix.\n  for (let rowIndex = 0; rowIndex < matrix.length; rowIndex += 1) {\n    for (let columnIndex = rowIndex + 1; columnIndex < matrix.length; columnIndex += 1) {\n      // Swap elements.\n      [\n        matrix[columnIndex][rowIndex],\n        matrix[rowIndex][columnIndex],\n      ] = [\n        matrix[rowIndex][columnIndex],\n        matrix[columnIndex][rowIndex],\n      ];\n    }\n  }\n\n  // Do horizontal reflection of the matrix.\n  for (let rowIndex = 0; rowIndex < matrix.length; rowIndex += 1) {\n    for (let columnIndex = 0; columnIndex < matrix.length / 2; columnIndex += 1) {\n      // Swap elements.\n      [\n        matrix[rowIndex][matrix.length - columnIndex - 1],\n        matrix[rowIndex][columnIndex],\n      ] = [\n        matrix[rowIndex][columnIndex],\n        matrix[rowIndex][matrix.length - columnIndex - 1],\n      ];\n    }\n  }\n\n  return matrix;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/unique-paths/README.md",
    "content": "# Unique Paths Problem\n\nA robot is located at the top-left corner of a `m x n` grid \n(marked 'Start' in the diagram below).\n\nThe robot can only move either down or right at any point in \ntime. The robot is trying to reach the bottom-right corner \nof the grid (marked 'Finish' in the diagram below).\n\nHow many possible unique paths are there?\n\n![Unique Paths](https://leetcode.com/static/images/problemset/robot_maze.png)\n\n## Examples\n\n**Example #1**\n\n```\nInput: m = 3, n = 2\nOutput: 3\nExplanation:\nFrom the top-left corner, there are a total of 3 ways to reach the bottom-right corner:\n1. Right -> Right -> Down\n2. Right -> Down -> Right\n3. Down -> Right -> Right\n```\n\n**Example #2**\n\n```\nInput: m = 7, n = 3\nOutput: 28\n```\n\n## Algorithms\n\n### Backtracking\n\nFirst thought that might came to mind is that we need to build a decision tree \nwhere `D` means moving down and `R` means moving right. For example in case\nof boars `width = 3` and `height = 2` we will have the following decision tree:\n\n```\n                START\n                /   \\\n               D     R\n             /     /   \\\n           R      D      R\n         /      /         \\\n        R      R            D\n\n       END    END          END\n```\n\nWe can see three unique branches here that is the answer to our problem.\n\n**Time Complexity**: `O(2 ^ n)` - roughly in worst case with square board\nof size `n`.\n\n**Auxiliary Space Complexity**: `O(m + n)` - since we need to store current path with\npositions.\n\n### Dynamic Programming\n\nLet's treat `BOARD[i][j]` as our sub-problem.\n\nSince we have restriction of moving only to the right\nand down we might say that number of unique paths to the current\ncell is a sum of numbers of unique paths to the cell above the\ncurrent one and to the cell to the left of current one.\n\n```\nBOARD[i][j] = BOARD[i - 1][j] + BOARD[i][j - 1]; // since we can only move down or right.\n```\n\nBase cases are:\n\n```\nBOARD[0][any] = 1; // only one way to reach any top slot.\nBOARD[any][0] = 1; // only one way to reach any slot in the leftmost column.\n```\n\nFor the board `3 x 2` our dynamic programming matrix will look like:\n\n|     | 0   | 1   | 1   |\n|:---:|:---:|:---:|:---:|\n|**0**| 0   | 1   | 1   |\n|**1**| 1   | 2   | 3   |\n\nEach cell contains the number of unique paths to it. We need \nthe bottom right one with number `3`.\n\n**Time Complexity**: `O(m * n)` - since we're going through each cell of the DP matrix.\n\n**Auxiliary Space Complexity**: `O(m * n)` - since we need to have DP matrix.\n\n### Pascal's Triangle Based\n\nThis question is actually another form of Pascal Triangle.\n\nThe corner of this rectangle is at `m + n - 2` line, and \nat `min(m, n) - 1` position of the Pascal's Triangle.\n\n## References\n\n- [LeetCode](https://leetcode.com/problems/unique-paths/description/)\n"
  },
  {
    "path": "src/algorithms/uncategorized/unique-paths/__test__/btUniquePaths.test.js",
    "content": "import btUniquePaths from '../btUniquePaths';\n\ndescribe('btUniquePaths', () => {\n  it('should find the number of unique paths on board', () => {\n    expect(btUniquePaths(3, 2)).toBe(3);\n    expect(btUniquePaths(7, 3)).toBe(28);\n    expect(btUniquePaths(3, 7)).toBe(28);\n    expect(btUniquePaths(10, 10)).toBe(48620);\n    expect(btUniquePaths(100, 1)).toBe(1);\n    expect(btUniquePaths(1, 100)).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/unique-paths/__test__/dpUniquePaths.test.js",
    "content": "import dpUniquePaths from '../dpUniquePaths';\n\ndescribe('dpUniquePaths', () => {\n  it('should find the number of unique paths on board', () => {\n    expect(dpUniquePaths(3, 2)).toBe(3);\n    expect(dpUniquePaths(7, 3)).toBe(28);\n    expect(dpUniquePaths(3, 7)).toBe(28);\n    expect(dpUniquePaths(10, 10)).toBe(48620);\n    expect(dpUniquePaths(100, 1)).toBe(1);\n    expect(dpUniquePaths(1, 100)).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/unique-paths/__test__/uniquePaths.test.js",
    "content": "import uniquePaths from '../uniquePaths';\n\ndescribe('uniquePaths', () => {\n  it('should find the number of unique paths on board', () => {\n    expect(uniquePaths(3, 2)).toBe(3);\n    expect(uniquePaths(7, 3)).toBe(28);\n    expect(uniquePaths(3, 7)).toBe(28);\n    expect(uniquePaths(10, 10)).toBe(48620);\n    expect(uniquePaths(100, 1)).toBe(1);\n    expect(uniquePaths(1, 100)).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/algorithms/uncategorized/unique-paths/btUniquePaths.js",
    "content": "/**\n * BACKTRACKING approach of solving Unique Paths problem.\n *\n * @param {number} width - Width of the board.\n * @param {number} height - Height of the board.\n * @param {number[][]} steps - The steps that have been already made.\n * @param {number} uniqueSteps - Total number of unique steps.\n * @return {number} - Number of unique paths.\n */\nexport default function btUniquePaths(width, height, steps = [[0, 0]], uniqueSteps = 0) {\n  // Fetch current position on board.\n  const currentPos = steps[steps.length - 1];\n\n  // Check if we've reached the end.\n  if (currentPos[0] === width - 1 && currentPos[1] === height - 1) {\n    // In case if we've reached the end let's increase total\n    // number of unique steps.\n    return uniqueSteps + 1;\n  }\n\n  // Let's calculate how many unique path we will have\n  // by going right and by going down.\n  let rightUniqueSteps = 0;\n  let downUniqueSteps = 0;\n\n  // Do right step if possible.\n  if (currentPos[0] < width - 1) {\n    steps.push([\n      currentPos[0] + 1,\n      currentPos[1],\n    ]);\n\n    // Calculate how many unique paths we'll get by moving right.\n    rightUniqueSteps = btUniquePaths(width, height, steps, uniqueSteps);\n\n    // BACKTRACK and try another move.\n    steps.pop();\n  }\n\n  // Do down step if possible.\n  if (currentPos[1] < height - 1) {\n    steps.push([\n      currentPos[0],\n      currentPos[1] + 1,\n    ]);\n\n    // Calculate how many unique paths we'll get by moving down.\n    downUniqueSteps = btUniquePaths(width, height, steps, uniqueSteps);\n\n    // BACKTRACK and try another move.\n    steps.pop();\n  }\n\n  // Total amount of unique steps will be equal to total amount of\n  // unique steps by going right plus total amount of unique steps\n  // by going down.\n  return rightUniqueSteps + downUniqueSteps;\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/unique-paths/dpUniquePaths.js",
    "content": "/**\n * DYNAMIC PROGRAMMING approach of solving Unique Paths problem.\n *\n * @param {number} width - Width of the board.\n * @param {number} height - Height of the board.\n * @return {number} - Number of unique paths.\n */\nexport default function dpUniquePaths(width, height) {\n  // Init board.\n  const board = Array(height).fill(null).map(() => {\n    return Array(width).fill(0);\n  });\n\n  // Base case.\n  // There is only one way of getting to board[0][any] and\n  // there is also only one way of getting to board[any][0].\n  // This is because we have a restriction of moving right\n  // and down only.\n  for (let rowIndex = 0; rowIndex < height; rowIndex += 1) {\n    for (let columnIndex = 0; columnIndex < width; columnIndex += 1) {\n      if (rowIndex === 0 || columnIndex === 0) {\n        board[rowIndex][columnIndex] = 1;\n      }\n    }\n  }\n\n  // Now, since we have this restriction of moving only to the right\n  // and down we might say that number of unique paths to the current\n  // cell is a sum of numbers of unique paths to the cell above the\n  // current one and to the cell to the left of current one.\n  for (let rowIndex = 1; rowIndex < height; rowIndex += 1) {\n    for (let columnIndex = 1; columnIndex < width; columnIndex += 1) {\n      const uniquesFromTop = board[rowIndex - 1][columnIndex];\n      const uniquesFromLeft = board[rowIndex][columnIndex - 1];\n      board[rowIndex][columnIndex] = uniquesFromTop + uniquesFromLeft;\n    }\n  }\n\n  return board[height - 1][width - 1];\n}\n"
  },
  {
    "path": "src/algorithms/uncategorized/unique-paths/uniquePaths.js",
    "content": "import pascalTriangle from '../../math/pascal-triangle/pascalTriangle';\n\n/**\n * @param {number} width\n * @param {number} height\n * @return {number}\n */\nexport default function uniquePaths(width, height) {\n  const pascalLine = width + height - 2;\n  const pascalLinePosition = Math.min(width, height) - 1;\n\n  return pascalTriangle(pascalLine)[pascalLinePosition];\n}\n"
  },
  {
    "path": "src/data-structures/bloom-filter/BloomFilter.js",
    "content": "export default class BloomFilter {\n  /**\n   * @param {number} size - the size of the storage.\n   */\n  constructor(size = 100) {\n    // Bloom filter size directly affects the likelihood of false positives.\n    // The bigger the size the lower the likelihood of false positives.\n    this.size = size;\n    this.storage = this.createStore(size);\n  }\n\n  /**\n   * @param {string} item\n   */\n  insert(item) {\n    const hashValues = this.getHashValues(item);\n\n    // Set each hashValue index to true.\n    hashValues.forEach((val) => this.storage.setValue(val));\n  }\n\n  /**\n   * @param {string} item\n   * @return {boolean}\n   */\n  mayContain(item) {\n    const hashValues = this.getHashValues(item);\n\n    for (let hashIndex = 0; hashIndex < hashValues.length; hashIndex += 1) {\n      if (!this.storage.getValue(hashValues[hashIndex])) {\n        // We know that the item was definitely not inserted.\n        return false;\n      }\n    }\n\n    // The item may or may not have been inserted.\n    return true;\n  }\n\n  /**\n   * Creates the data store for our filter.\n   * We use this method to generate the store in order to\n   * encapsulate the data itself and only provide access\n   * to the necessary methods.\n   *\n   * @param {number} size\n   * @return {Object}\n   */\n  createStore(size) {\n    const storage = [];\n\n    // Initialize all indexes to false\n    for (let storageCellIndex = 0; storageCellIndex < size; storageCellIndex += 1) {\n      storage.push(false);\n    }\n\n    const storageInterface = {\n      getValue(index) {\n        return storage[index];\n      },\n      setValue(index) {\n        storage[index] = true;\n      },\n    };\n\n    return storageInterface;\n  }\n\n  /**\n   * @param {string} item\n   * @return {number}\n   */\n  hash1(item) {\n    let hash = 0;\n\n    for (let charIndex = 0; charIndex < item.length; charIndex += 1) {\n      const char = item.charCodeAt(charIndex);\n      hash = (hash << 5) + hash + char;\n      hash &= hash; // Convert to 32bit integer\n      hash = Math.abs(hash);\n    }\n\n    return hash % this.size;\n  }\n\n  /**\n   * @param {string} item\n   * @return {number}\n   */\n  hash2(item) {\n    let hash = 5381;\n\n    for (let charIndex = 0; charIndex < item.length; charIndex += 1) {\n      const char = item.charCodeAt(charIndex);\n      hash = (hash << 5) + hash + char; /* hash * 33 + c */\n    }\n\n    return Math.abs(hash % this.size);\n  }\n\n  /**\n   * @param {string} item\n   * @return {number}\n   */\n  hash3(item) {\n    let hash = 0;\n\n    for (let charIndex = 0; charIndex < item.length; charIndex += 1) {\n      const char = item.charCodeAt(charIndex);\n      hash = (hash << 5) - hash;\n      hash += char;\n      hash &= hash; // Convert to 32bit integer\n    }\n\n    return Math.abs(hash % this.size);\n  }\n\n  /**\n   * Runs all 3 hash functions on the input and returns an array of results.\n   *\n   * @param {string} item\n   * @return {number[]}\n   */\n  getHashValues(item) {\n    return [\n      this.hash1(item),\n      this.hash2(item),\n      this.hash3(item),\n    ];\n  }\n}\n"
  },
  {
    "path": "src/data-structures/bloom-filter/README.md",
    "content": "# Bloom Filter\n\n_Read this in other languages:_\n[_Русский_](README.ru-RU.md),\n[_Português_](README.pt-BR.md),\n[_Українська_](README.uk-UA.md)\n\nA **bloom filter** is a space-efficient probabilistic\ndata structure designed to test whether an element\nis present in a set. It is designed to be blazingly\nfast and use minimal memory at the cost of potential\nfalse positives. False positive matches are possible,\nbut false negatives are not – in other words, a query\nreturns either \"possibly in set\" or \"definitely not in set\".\n\nBloom proposed the technique for applications where the\namount of source data would require an impractically large\namount of memory if \"conventional\" error-free hashing\ntechniques were applied.\n\n## Algorithm description\n\nAn empty Bloom filter is a bit array of `m` bits, all\nset to `0`. There must also be `k` different hash functions\ndefined, each of which maps or hashes some set element to\none of the `m` array positions, generating a uniform random\ndistribution. Typically, `k` is a constant, much smaller\nthan `m`, which is proportional to the number of elements\nto be added; the precise choice of `k` and the constant of\nproportionality of `m` are determined by the intended\nfalse positive rate of the filter.\n\nHere is an example of a Bloom filter, representing the\nset `{x, y, z}`. The colored arrows show the positions\nin the bit array that each set element is mapped to. The\nelement `w` is not in the set `{x, y, z}`, because it\nhashes to one bit-array position containing `0`. For\nthis figure, `m = 18` and `k = 3`.\n\n![Bloom Filter](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)\n\n## Operations\n\nThere are two main operations a bloom filter can\nperform: _insertion_ and _search_. Search may result in\nfalse positives. Deletion is not possible.\n\nIn other words, the filter can take in items. When\nwe go to check if an item has previously been\ninserted, it can tell us either \"no\" or \"maybe\".\n\nBoth insertion and search are `O(1)` operations.\n\n## Making the filter\n\nA bloom filter is created by allotting a certain size.\nIn our example, we use `100` as a default length. All\nlocations are initialized to `false`.\n\n### Insertion\n\nDuring insertion, a number of hash functions,\nin our case `3` hash functions, are used to create\nhashes of the input. These hash functions output\nindexes. At every index received, we simply change\nthe value in our bloom filter to `true`.\n\n### Search\n\nDuring a search, the same hash functions are called\nand used to hash the input. We then check if the\nindexes received _all_ have a value of `true` inside\nour bloom filter. If they _all_ have a value of\n`true`, we know that the bloom filter may have had\nthe value previously inserted.\n\nHowever, it's not certain, because it's possible\nthat other values previously inserted flipped the\nvalues to `true`. The values aren't necessarily\n`true` due to the item currently being searched for.\nAbsolute certainty is impossible unless only a single\nitem has previously been inserted.\n\nWhile checking the bloom filter for the indexes\nreturned by our hash functions, if even one of them\nhas a value of `false`, we definitively know that the\nitem was not previously inserted.\n\n## False Positives\n\nThe probability of false positives is determined by\nthree factors: the size of the bloom filter, the\nnumber of hash functions we use, and the number\nof items that have been inserted into the filter.\n\nThe formula to calculate probability of a false positive is:\n\n( 1 - e <sup>-kn/m</sup> ) <sup>k</sup>\n\n`k` = number of hash functions\n\n`m` = filter size\n\n`n` = number of items inserted\n\nThese variables, `k`, `m`, and `n`, should be picked based\non how acceptable false positives are. If the values\nare picked and the resulting probability is too high,\nthe values should be tweaked and the probability\nre-calculated.\n\n## Applications\n\nA bloom filter can be used on a blogging website. If\nthe goal is to show readers only articles that they\nhave never seen before, a bloom filter is perfect.\nIt can store hashed values based on the articles. After\na user reads a few articles, they can be inserted into\nthe filter. The next time the user visits the site,\nthose articles can be filtered out of the results.\n\nSome articles will inevitably be filtered out by mistake,\nbut the cost is acceptable. It's ok if a user never sees\na few articles as long as they have other, brand new ones\nto see every time they visit the site.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Bloom_filter)\n- [Bloom Filters by Example](http://llimllib.github.io/bloomfilter-tutorial/)\n- [Calculating False Positive Probability](https://hur.st/bloomfilter/?n=4&p=&m=18&k=3)\n- [Bloom Filters on Medium](https://blog.medium.com/what-are-bloom-filters-1ec2a50c68ff)\n- [Bloom Filters on YouTube](https://www.youtube.com/watch?v=bEmBh1HtYrw)\n"
  },
  {
    "path": "src/data-structures/bloom-filter/README.pt-BR.md",
    "content": "# Filtro Bloom (Bloom Filter)\n\nO **bloom filter** é uma estrutura de dados probabilística\nespaço-eficiente designada para testar se um elemento está\nou não presente em um conjunto de dados. Foi projetado para ser\nincrivelmente rápida e utilizar o mínimo de memória ao \npotencial custo de um falso-positivo. Correspondências \n_falsas positivas_ são possíveis, contudo _falsos negativos_ \nnão são - em outras palavras, a consulta retorna \n\"possivelmente no conjunto\" ou \"definitivamente não no conjunto\".\n\nBloom propôs a técnica para aplicações onde a quantidade \nde entrada de dados exigiria uma alocação de memória\nimpraticavelmente grande se as \"convencionais\" técnicas\nerror-free hashing fossem aplicadas.\n\n## Descrição do algoritmo\n\nUm filtro Bloom vazio é um _bit array_ de `m` bits, todos\ndefinidos como `0`. Também deverá haver diferentes funções\nde hash `k` definidas, cada um dos quais mapeia e produz hash\npara um dos elementos definidos em uma das posições `m` da\n _array_, gerando uma distribuição aleatória e uniforme.\nNormalmente, `k` é uma constante, muito menor do que `m`,\npelo qual é proporcional ao número de elements a ser adicionado;\na escolha precisa de `k` e a constante de proporcionalidade de `m`\nsão determinadas pela taxa de falsos positivos planejado do filtro.\n\nAqui está um exemplo de um filtro Bloom, representando o\nconjunto `{x, y, z}`. As flechas coloridas demonstram as\nposições no _bit array_ em que cada elemento é mapeado.\nO elemento `w` não está definido dentro de `{x, y, z}`,\nporque este produz hash para uma posição de array de bits\ncontendo `0`. Para esta imagem: `m = 18` e `k = 3`.\n\n![Bloom Filter](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)\n\n## Operações\n\nExistem duas operações principais que o filtro Bloom pode operar:\n_inserção_ e _pesquisa_. A pesquisa pode resultar em falsos\npositivos. Remoção não é possível.\n\nEm outras palavras, o filtro pode receber itens. Quando\nvamos verificar se um item já foi anteriormente\ninserido, ele poderá nos dizer \"não\" ou \"talvez\".\n\nAmbas as inserções e pesquisas são operações `O(1)`.\n\n## Criando o filtro\n\nUm filtro Bloom é criado ao alocar um certo tamanho.\nNo nosso exemplo, nós utilizamos `100` como tamanho padrão.\nTodas as posições são initializadas como `false`.\n\n### Inserção\n\nDurante a inserção, um número de função hash, no nosso caso `3`\nfunções de hash, são utilizadas para criar hashes de uma entrada.\nEstas funções de hash emitem saída de índices. A cada índice\nrecebido, nós simplismente trocamos o valor de nosso filtro\nBloom para `true`.\n\n### Pesquisa\n\nDurante a pesquisa, a mesma função de hash é chamada\ne usada para emitir hash da entrada. Depois nós checamos\nse _todos_ os indices recebidos possuem o valor `true`\ndentro de nosso filtro Bloom. Caso _todos_ possuam o valor\n`true`, nós sabemos que o filtro Bloom pode ter tido\no valor inserido anteriormente.\n\nContudo, isto não é certeza, porque é possível que outros\nvalores anteriormente inseridos trocaram o valor para `true`.\nOs valores não são necessariamente `true` devido ao ítem\natualmente sendo pesquisado. A certeza absoluta é impossível,\na não ser que apenas um item foi inserido anteriormente.\n\nDurante a checagem do filtro Bloom para índices retornados\npela nossa função de hash, mesmo que apenas um deles possua\nvalor como `false`, nós definitivamente sabemos que o ítem\nnão foi anteriormente inserido.\n\n## Falso Positivos\n\nA probabilidade de falso positivos é determinado por\ntrês fatores: o tamanho do filtro de Bloom, o número de \nfunções de hash que utilizados, e o número de itens que\nforam inseridos dentro do filtro.\n\nA formula para calcular a probabilidade de um falso positivo é:\n\n( 1 - e <sup>-kn/m</sup> ) <sup>k</sup>\n\n`k` = número de funções de hash\n\n`m` = tamanho do filtro\n\n`n` = número de itens inserido\n\nEstas variáveis, `k`, `m` e `n`, devem ser escolhidas baseado\nem quanto aceitável são os falsos positivos. Se os valores\nescolhidos resultam em uma probabilidade muito alta, então\nos valores devem ser ajustados e a probabilidade recalculada.\n\n## Aplicações\n\nUm filtro Bloom pode ser utilizado em uma página de Blog.\nSe o objetivo é mostrar aos leitores somente os artigos\nem que eles nunca viram, então o filtro Bloom é perfeito \npara isso. Ele pode armazenar hashes baseados nos artigos.\nDepois que um usuário lê alguns artigos, eles podem ser\ninseridos dentro do filtro. Na próxima vez que o usuário\nvisitar o Blog, aqueles artigos poderão ser filtrados (eliminados) \ndo resultado.\n\nAlguns artigos serão inevitavelmente filtrados (eliminados) \npor engano, mas o custo é aceitável. Tudo bem se um usuário nunca\nver alguns poucos artigos, desde que tenham outros novos\npara ver toda vez que eles visitam o site. \n\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Bloom_filter)\n- [Bloom Filters by Example](http://llimllib.github.io/bloomfilter-tutorial/)\n- [Calculating False Positive Probability](https://hur.st/bloomfilter/?n=4&p=&m=18&k=3)\n- [Bloom Filters on Medium](https://blog.medium.com/what-are-bloom-filters-1ec2a50c68ff)\n- [Bloom Filters on YouTube](https://www.youtube.com/watch?v=bEmBh1HtYrw)\n"
  },
  {
    "path": "src/data-structures/bloom-filter/README.ru-RU.md",
    "content": "# Фильтр Блума\n\n**Фильтр Блума** - это пространственно-эффективная вероятностная структура данных, созданная для проверки наличия элемента\nв множестве. Он спроектирован невероятно быстрым при минимальном использовании памяти ценой потенциальных ложных срабатываний.\nСуществует возможность получить ложноположительное срабатывание (элемента в множестве нет, но структура данных сообщает,\nчто он есть), но не ложноотрицательное. Другими словами, очередь возвращает или \"возможно в наборе\", или \"определённо не\nв наборе\". Фильтр Блума может использовать любой объём памяти, однако чем он больше, тем меньше вероятность ложного\nсрабатывания. \n\nБлум предложил эту технику для применения в областях, где количество исходных данных потребовало бы непрактично много \nпамяти, в случае применения условно безошибочных техник хеширования.\n\n## Описание алгоритма\n\nПустой фильтр Блума представлен битовым массивом из `m` битов, все биты которого обнулены. Должно быть определено `k`\nнезависимых хеш-функций, отображающих каждый элемент множества в одну из `m` позиций в массиве, генерируя единообразное\nслучайное распределение. Обычно `k` задана константой, которая много меньше `m` и пропорциональна\nколичеству добавляемых элементов; точный выбор `k` и постоянной пропорциональности `m` определяются уровнем ложных\nсрабатываний фильтра.\n\nВот пример Блум фильтра, представляющего набор `{x, y, z}`. Цветные стрелки показывают позиции в битовом массиве,\nкоторым привязан каждый элемент набора. Элемент `w` не в наборе `{x, y, z}`, потому что он привязан к позиции в битовом\nмассиве, равной `0`. Для этой формы , `m = 18`, а `k = 3`.\n\nФильтр Блума представляет собой битовый массив из `m` бит. Изначально, когда структура данных хранит пустое множество, все\n`m` бит обнулены. Пользователь должен определить `k` независимых хеш-функций `h1`, …, `hk`,\nотображающих каждый элемент в одну из `m` позиций битового массива достаточно равномерным образом.\n\nДля добавления элемента e необходимо записать единицы на каждую из позиций `h1(e)`, …, `hk(e)`\nбитового массива.\n\nДля проверки принадлежности элемента `e` к множеству хранимых элементов, необходимо проверить состояние битов\n`h1(e)`, …, `hk(e)`. Если хотя бы один из них равен нулю, элемент не может принадлежать множеству\n(иначе бы при его добавлении все эти биты были установлены). Если все они равны единице, то структура данных сообщает,\nчто `е` принадлежит множеству. При этом может возникнуть две ситуации: либо элемент действительно принадлежит множеству,\nлибо все эти биты оказались установлены по случайности при добавлении других элементов, что и является источником ложных\nсрабатываний в этой структуре данных.\n\n![Фильтр Блума](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)\n\n## Применения\n\nФильтр Блума может быть использован для блогов. Если цель состоит в том, чтобы показать читателям только те статьи,\nкоторые они ещё не видели, фильтр блума идеален. Он может содержать хешированные значения, соответствующие статье. После\nтого, как пользователь прочитал несколько статей, они могут быть помещены в фильтр. В следующий раз, когда пользователь\nпосетит сайт, эти статьи могут быть убраны из результатов с помощью фильтра.\n\nНекоторые статьи неизбежно будут отфильтрованы по ошибке, но цена приемлема. То, что пользователь не увидит несколько\nстатей в полне приемлемо, принимая во внимание тот факт, что ему всегда показываются другие новые статьи при каждом\nновом посещении.\n\n## Ссылки\n\n- [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)\n- [Фильтр Блума на Хабре](https://habr.com/ru/post/112069/)\n"
  },
  {
    "path": "src/data-structures/bloom-filter/README.uk-UA.md",
    "content": "# Фільтр Блума\n\n**Фільтр Блума** - це просторово-ефективна ймовірна структура даних, створена для перевірки наявності елемента\nу множині. Він спроектований неймовірно швидким за мінімального використання пам'яті ціною потенційних помилкових спрацьовувань.\nІснує можливість отримати хибнопозитивне спрацьовування (елемента в безлічі немає, але структура даних повідомляє,\nщо він є), але не хибнонегативне. Іншими словами, черга повертає або \"можливо в наборі\", або \"певно не\nу наборі\". Фільтр Блума може використовувати будь-який обсяг пам'яті, проте чим він більший, тим менша вірогідність помилкового\nспрацьовування.\n\nБлум запропонував цю техніку для застосування в областях, де кількість вихідних даних потребувала б непрактично багато\nпам'яті, у разі застосування умовно безпомилкових технік хешування.\n\n## Опис алгоритму\n\nПорожній фільтр Блума представлений бітовим масивом з `m` бітів, всі біти якого обнулені. Має бути визначено `k`\nнезалежних хеш-функцій, що відображають кожен елемент множини в одну з `m` позицій у масиві, генеруючи однакове\nвипадковий розподіл. Зазвичай `k` задана константою, яка набагато менше `m` і пропорційна\nкількості елементів, що додаються; точний вибір `k` та постійної пропорційності `m` визначаються рівнем хибних\nспрацьовувань фільтра.\n\nОсь приклад Блум фільтра, що представляє набір `{x, y, z}`. Кольорові стрілки показують позиції в бітовому масиві,\nяким прив'язаний кожен елемент набору. Елемент `w` не в наборі `{x, y, z}`, тому що він прив'язаний до позиції в бітовому\nмасиві, що дорівнює `0`. Для цієї форми, `m = 18`, а `k = 3`.\n\nФільтр Блума є бітовий масив з `m` біт. Спочатку, коли структура даних зберігає порожню множину, всі\nm біт обнулені. Користувач повинен визначити `k` незалежних хеш-функцій `h1`, …, `hk`,\nщо відображають кожен елемент в одну з m позицій бітового масиву досить рівномірним чином.\n\nДля додавання елемента e необхідно записати одиниці на кожну з позицій `h1(e)`, …, `hk(e)`\nбітового масиву.\n\nДля перевірки приналежності елемента `e` до безлічі елементів, що зберігаються, необхідно перевірити стан бітів\n`h1(e)`, …, `hk(e)`. Якщо хоча б один з них дорівнює нулю, елемент не може належати множині\n(інакше при його додаванні всі ці біти були встановлені). Якщо вони рівні одиниці, то структура даних повідомляє,\nщо `е` належить безлічі. При цьому може виникнути дві ситуації: або елемент дійсно належить множині,\nабо всі ці біти виявилися встановлені випадково при додаванні інших елементів, що і є джерелом помилкових\nспрацьовувань у цій структурі даних.\n\n![Фільтр Блума](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)\n\n## Застосування\n\nФільтр Блума може бути використаний для блогів. Якщо мета полягає в тому, щоб показати читачам лише ті статті,\nякі вони ще не бачили, фільтр блуму ідеальний. Він може містити значення, що хешуються, відповідні статті. Після\nтого, як користувач прочитав кілька статей, вони можуть бути поміщені у фільтр. Наступного разу, коли користувач\nвідвідає сайт, ці статті можуть бути вилучені з результатів за допомогою фільтра.\n\nДеякі статті неминуче будуть відфільтровані помилково, але ціна прийнятна. Те, що користувач не побачить дещо\nстатей цілком прийнятно, беручи до уваги той факт, що йому завжди показуються інші нові статті при кожному\nновому відвідуванні.\n\n## Посилання\n\n- [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)\n"
  },
  {
    "path": "src/data-structures/bloom-filter/__test__/BloomFilter.test.js",
    "content": "import BloomFilter from '../BloomFilter';\n\ndescribe('BloomFilter', () => {\n  let bloomFilter;\n  const people = [\n    'Bruce Wayne',\n    'Clark Kent',\n    'Barry Allen',\n  ];\n\n  beforeEach(() => {\n    bloomFilter = new BloomFilter();\n  });\n\n  it('should have methods named \"insert\" and \"mayContain\"', () => {\n    expect(typeof bloomFilter.insert).toBe('function');\n    expect(typeof bloomFilter.mayContain).toBe('function');\n  });\n\n  it('should create a new filter store with the appropriate methods', () => {\n    const store = bloomFilter.createStore(18);\n    expect(typeof store.getValue).toBe('function');\n    expect(typeof store.setValue).toBe('function');\n  });\n\n  it('should hash deterministically with all 3 hash functions', () => {\n    const str1 = 'apple';\n\n    expect(bloomFilter.hash1(str1)).toEqual(bloomFilter.hash1(str1));\n    expect(bloomFilter.hash2(str1)).toEqual(bloomFilter.hash2(str1));\n    expect(bloomFilter.hash3(str1)).toEqual(bloomFilter.hash3(str1));\n\n    expect(bloomFilter.hash1(str1)).toBe(14);\n    expect(bloomFilter.hash2(str1)).toBe(43);\n    expect(bloomFilter.hash3(str1)).toBe(10);\n\n    const str2 = 'orange';\n\n    expect(bloomFilter.hash1(str2)).toEqual(bloomFilter.hash1(str2));\n    expect(bloomFilter.hash2(str2)).toEqual(bloomFilter.hash2(str2));\n    expect(bloomFilter.hash3(str2)).toEqual(bloomFilter.hash3(str2));\n\n    expect(bloomFilter.hash1(str2)).toBe(0);\n    expect(bloomFilter.hash2(str2)).toBe(61);\n    expect(bloomFilter.hash3(str2)).toBe(10);\n  });\n\n  it('should create an array with 3 hash values', () => {\n    expect(bloomFilter.getHashValues('abc').length).toBe(3);\n    expect(bloomFilter.getHashValues('abc')).toEqual([66, 63, 54]);\n  });\n\n  it('should insert strings correctly and return true when checking for inserted values', () => {\n    people.forEach((person) => bloomFilter.insert(person));\n\n    expect(bloomFilter.mayContain('Bruce Wayne')).toBe(true);\n    expect(bloomFilter.mayContain('Clark Kent')).toBe(true);\n    expect(bloomFilter.mayContain('Barry Allen')).toBe(true);\n\n    expect(bloomFilter.mayContain('Tony Stark')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/disjoint-set/DisjointSet.js",
    "content": "import DisjointSetItem from './DisjointSetItem';\n\nexport default class DisjointSet {\n  /**\n   * @param {function(value: *)} [keyCallback]\n   */\n  constructor(keyCallback) {\n    this.keyCallback = keyCallback;\n    this.items = {};\n  }\n\n  /**\n   * @param {*} itemValue\n   * @return {DisjointSet}\n   */\n  makeSet(itemValue) {\n    const disjointSetItem = new DisjointSetItem(itemValue, this.keyCallback);\n\n    if (!this.items[disjointSetItem.getKey()]) {\n      // Add new item only in case if it not presented yet.\n      this.items[disjointSetItem.getKey()] = disjointSetItem;\n    }\n\n    return this;\n  }\n\n  /**\n   * Find set representation node.\n   *\n   * @param {*} itemValue\n   * @return {(string|null)}\n   */\n  find(itemValue) {\n    const templateDisjointItem = new DisjointSetItem(itemValue, this.keyCallback);\n\n    // Try to find item itself;\n    const requiredDisjointItem = this.items[templateDisjointItem.getKey()];\n\n    if (!requiredDisjointItem) {\n      return null;\n    }\n\n    return requiredDisjointItem.getRoot().getKey();\n  }\n\n  /**\n   * Union by rank.\n   *\n   * @param {*} valueA\n   * @param {*} valueB\n   * @return {DisjointSet}\n   */\n  union(valueA, valueB) {\n    const rootKeyA = this.find(valueA);\n    const rootKeyB = this.find(valueB);\n\n    if (rootKeyA === null || rootKeyB === null) {\n      throw new Error('One or two values are not in sets');\n    }\n\n    if (rootKeyA === rootKeyB) {\n      // In case if both elements are already in the same set then just return its key.\n      return this;\n    }\n\n    const rootA = this.items[rootKeyA];\n    const rootB = this.items[rootKeyB];\n\n    if (rootA.getRank() < rootB.getRank()) {\n      // If rootB's tree is bigger then make rootB to be a new root.\n      rootB.addChild(rootA);\n\n      return this;\n    }\n\n    // If rootA's tree is bigger then make rootA to be a new root.\n    rootA.addChild(rootB);\n\n    return this;\n  }\n\n  /**\n   * @param {*} valueA\n   * @param {*} valueB\n   * @return {boolean}\n   */\n  inSameSet(valueA, valueB) {\n    const rootKeyA = this.find(valueA);\n    const rootKeyB = this.find(valueB);\n\n    if (rootKeyA === null || rootKeyB === null) {\n      throw new Error('One or two values are not in sets');\n    }\n\n    return rootKeyA === rootKeyB;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/disjoint-set/DisjointSetAdhoc.js",
    "content": "/**\n * The minimalistic (ad hoc) version of a DisjointSet (or a UnionFind) data structure\n * that doesn't have external dependencies and that is easy to copy-paste and\n * use during the coding interview if allowed by the interviewer (since many\n * data structures in JS are missing).\n *\n * Time Complexity:\n *\n * - Constructor: O(N)\n * - Find: O(α(N))\n * - Union: O(α(N))\n * - Connected: O(α(N))\n *\n * Where N is the number of vertices in the graph.\n * α refers to the Inverse Ackermann function.\n * In practice, we assume it's a constant.\n * In other words, O(α(N)) is regarded as O(1) on average.\n */\nclass DisjointSetAdhoc {\n  /**\n   * Initializes the set of specified size.\n   * @param {number} size\n   */\n  constructor(size) {\n    // The index of a cell is an id of the node in a set.\n    // The value of a cell is an id (index) of the root node.\n    // By default, the node is a parent of itself.\n    this.roots = new Array(size).fill(0).map((_, i) => i);\n\n    // Using the heights array to record the height of each node.\n    // By default each node has a height of 1 because it has no children.\n    this.heights = new Array(size).fill(1);\n  }\n\n  /**\n   * Finds the root of node `a`\n   * @param {number} a\n   * @returns {number}\n   */\n  find(a) {\n    if (a === this.roots[a]) return a;\n    this.roots[a] = this.find(this.roots[a]);\n    return this.roots[a];\n  }\n\n  /**\n   * Joins the `a` and `b` nodes into same set.\n   * @param {number} a\n   * @param {number} b\n   * @returns {number}\n   */\n  union(a, b) {\n    const aRoot = this.find(a);\n    const bRoot = this.find(b);\n\n    if (aRoot === bRoot) return;\n\n    if (this.heights[aRoot] > this.heights[bRoot]) {\n      this.roots[bRoot] = aRoot;\n    } else if (this.heights[aRoot] < this.heights[bRoot]) {\n      this.roots[aRoot] = bRoot;\n    } else {\n      this.roots[bRoot] = aRoot;\n      this.heights[aRoot] += 1;\n    }\n  }\n\n  /**\n   * Checks if `a` and `b` belong to the same set.\n   * @param {number} a\n   * @param {number} b\n   */\n  connected(a, b) {\n    return this.find(a) === this.find(b);\n  }\n}\n\nexport default DisjointSetAdhoc;\n"
  },
  {
    "path": "src/data-structures/disjoint-set/DisjointSetItem.js",
    "content": "export default class DisjointSetItem {\n  /**\n   * @param {*} value\n   * @param {function(value: *)} [keyCallback]\n   */\n  constructor(value, keyCallback) {\n    this.value = value;\n    this.keyCallback = keyCallback;\n    /** @var {DisjointSetItem} this.parent */\n    this.parent = null;\n    this.children = {};\n  }\n\n  /**\n   * @return {*}\n   */\n  getKey() {\n    // Allow user to define custom key generator.\n    if (this.keyCallback) {\n      return this.keyCallback(this.value);\n    }\n\n    // Otherwise use value as a key by default.\n    return this.value;\n  }\n\n  /**\n   * @return {DisjointSetItem}\n   */\n  getRoot() {\n    return this.isRoot() ? this : this.parent.getRoot();\n  }\n\n  /**\n   * @return {boolean}\n   */\n  isRoot() {\n    return this.parent === null;\n  }\n\n  /**\n   * Rank basically means the number of all ancestors.\n   *\n   * @return {number}\n   */\n  getRank() {\n    if (this.getChildren().length === 0) {\n      return 0;\n    }\n\n    let rank = 0;\n\n    /** @var {DisjointSetItem} child */\n    this.getChildren().forEach((child) => {\n      // Count child itself.\n      rank += 1;\n\n      // Also add all children of current child.\n      rank += child.getRank();\n    });\n\n    return rank;\n  }\n\n  /**\n   * @return {DisjointSetItem[]}\n   */\n  getChildren() {\n    return Object.values(this.children);\n  }\n\n  /**\n   * @param {DisjointSetItem} parentItem\n   * @param {boolean} forceSettingParentChild\n   * @return {DisjointSetItem}\n   */\n  setParent(parentItem, forceSettingParentChild = true) {\n    this.parent = parentItem;\n    if (forceSettingParentChild) {\n      parentItem.addChild(this);\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {DisjointSetItem} childItem\n   * @return {DisjointSetItem}\n   */\n  addChild(childItem) {\n    this.children[childItem.getKey()] = childItem;\n    childItem.setParent(this, false);\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/disjoint-set/README.md",
    "content": "# Disjoint Set\n\n_Read this in other languages:_\n[_Русский_](README.ru-RU.md),\n[_Português_](README.pt-BR.md),\n[_Українська_](README.uk-UA.md)\n\n**Disjoint-set** data structure (also called a union–find data structure or merge–find set) is a data\nstructure that tracks a set of elements partitioned into a number of disjoint (non-overlapping) subsets.\nIt provides near-constant-time operations (bounded by the inverse Ackermann function) to _add new sets_,\nto _merge existing sets_, and to _determine whether elements are in the same set_.\nIn 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.\n\n![disjoint set](https://upload.wikimedia.org/wikipedia/commons/6/67/Dsu_disjoint_sets_init.svg)\n\n_MakeSet_ creates 8 singletons.\n\n![disjoint set](https://upload.wikimedia.org/wikipedia/commons/a/ac/Dsu_disjoint_sets_final.svg)\n\nAfter some operations of _Union_, some sets are grouped together.\n\n## Implementation\n\n- [DisjointSet.js](./DisjointSet.js)\n- [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).\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)\n- [By Abdul Bari on YouTube](https://www.youtube.com/watch?v=wU6udHRIkcc&index=14&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/disjoint-set/README.pt-BR.md",
    "content": "# Conjunto Disjunto (Disjoint Set)\n\n**Conjunto Disjunto**\n\n**Conjunto Disjunto** é uma estrutura de dados (também chamado de\nestrutura de dados de union–find ou merge–find) é uma estrutura de dados\nque rastreia um conjunto de elementos particionados em um número de\nsubconjuntos separados (sem sobreposição).\nEle fornece operações de tempo quase constante (limitadas pela função\ninversa de Ackermann) para *adicionar novos conjuntos*, para \n*mesclar/fundir conjuntos existentes* e para *determinar se os elementos\nestão no mesmo conjunto*.\nAlém de muitos outros usos (veja a seção Applications), conjuntos disjuntos\ndesempenham um papel fundamental no algoritmo de Kruskal para encontrar a\nárvore geradora mínima de um grafo (graph).\n\n![disjoint set](https://upload.wikimedia.org/wikipedia/commons/6/67/Dsu_disjoint_sets_init.svg)\n\n*MakeSet* cria 8 singletons.\n\n![disjoint set](https://upload.wikimedia.org/wikipedia/commons/a/ac/Dsu_disjoint_sets_final.svg)\n\nDepois de algumas operações de *Uniões*, alguns conjuntos são agrupados juntos.\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)\n- [By Abdul Bari on YouTube](https://www.youtube.com/watch?v=wU6udHRIkcc&index=14&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/disjoint-set/README.ru-RU.md",
    "content": "# Система непересекающихся множеств\n\n**Система непересекающихся множеств** это структура данных (также называемая структурой данной поиска пересечения или\nмножеством поиска слияния), которая управляет множеством элементов, разбитых на несколько непересекающихся подмножеств.\nОна предоставляет около-константное время выполнения операций (ограниченное обратной функцией Акерманна) по *добавлению\nновых множеств*, *слиянию существующих множеств* и *опеределению, относятся ли элементы к одному и тому же множеству*.\n\nПрименяется для хранения компонент связности в графах, в частности, алгоритму Краскала необходима подобная структура\nданных для эффективной реализации.\n\nОсновные операции:\n\n- *MakeSet(x)* - создаёт одноэлементное множество {x},\n- *Find(x)* - возвращает идентификатор множества, содержащего элемент x,\n- *Union(x,y)* - объединение множеств, содержащих x и y.\n\nПосле некоторых операций *объединения*, некоторые множества собраны вместе\n\n## Ссылки\n- [СНМ на 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)\n- [СНМ на YouTube](https://www.youtube.com/watch?v=bXBHYqNeBLo)\n"
  },
  {
    "path": "src/data-structures/disjoint-set/README.uk-UA.md",
    "content": "# Система неперетинних множин\n\n**Система неперетинних множин** це структура даних (також звана структурою даної пошуку перетину або\nбезліччю пошуку злиття), яка управляє безліччю елементів, розбитих на кілька підмножин, що не перетинаються.\nВона надає близько-константний час виконання операцій (обмежений зворотною функцією Акерманна) за додаванням\nнових множин, *злиття існуючих множин і *випередження, чи відносяться елементи до одного і того ж безлічі.\n\nЗастосовується для зберігання компонентів зв'язності в графах, зокрема, алгоритму Фарбала необхідна подібна структура\nданих для ефективної реалізації.\n\nОсновні операції:\n\n- _MakeSet(x)_ - створює одноелементне безліч {x},\n- _Find(x)_ - повертає ідентифікатор множини, що містить елемент x,\n- _Union(x,y)_ - об'єднання множин, що містять x та y.\n\nПісля деяких операцій _об'єднання_, деякі множини зібрані разом.\n\n## Посилання\n\n- [СНМ на 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)\n- [СНМ на YouTube](https://www.youtube.com/watch?v=5XwRPwLnK6I)\n"
  },
  {
    "path": "src/data-structures/disjoint-set/__test__/DisjointSet.test.js",
    "content": "import DisjointSet from '../DisjointSet';\n\ndescribe('DisjointSet', () => {\n  it('should throw error when trying to union and check not existing sets', () => {\n    function mergeNotExistingSets() {\n      const disjointSet = new DisjointSet();\n\n      disjointSet.union('A', 'B');\n    }\n\n    function checkNotExistingSets() {\n      const disjointSet = new DisjointSet();\n\n      disjointSet.inSameSet('A', 'B');\n    }\n\n    expect(mergeNotExistingSets).toThrow();\n    expect(checkNotExistingSets).toThrow();\n  });\n\n  it('should do basic manipulations on disjoint set', () => {\n    const disjointSet = new DisjointSet();\n\n    expect(disjointSet.find('A')).toBeNull();\n    expect(disjointSet.find('B')).toBeNull();\n\n    disjointSet.makeSet('A');\n\n    expect(disjointSet.find('A')).toBe('A');\n    expect(disjointSet.find('B')).toBeNull();\n\n    disjointSet.makeSet('B');\n\n    expect(disjointSet.find('A')).toBe('A');\n    expect(disjointSet.find('B')).toBe('B');\n\n    disjointSet.makeSet('C');\n\n    expect(disjointSet.inSameSet('A', 'B')).toBe(false);\n\n    disjointSet.union('A', 'B');\n\n    expect(disjointSet.find('A')).toBe('A');\n    expect(disjointSet.find('B')).toBe('A');\n    expect(disjointSet.inSameSet('A', 'B')).toBe(true);\n    expect(disjointSet.inSameSet('B', 'A')).toBe(true);\n    expect(disjointSet.inSameSet('A', 'C')).toBe(false);\n\n    disjointSet.union('A', 'A');\n\n    disjointSet.union('B', 'C');\n\n    expect(disjointSet.find('A')).toBe('A');\n    expect(disjointSet.find('B')).toBe('A');\n    expect(disjointSet.find('C')).toBe('A');\n\n    expect(disjointSet.inSameSet('A', 'B')).toBe(true);\n    expect(disjointSet.inSameSet('B', 'C')).toBe(true);\n    expect(disjointSet.inSameSet('A', 'C')).toBe(true);\n\n    disjointSet\n      .makeSet('E')\n      .makeSet('F')\n      .makeSet('G')\n      .makeSet('H')\n      .makeSet('I');\n\n    disjointSet\n      .union('E', 'F')\n      .union('F', 'G')\n      .union('G', 'H')\n      .union('H', 'I');\n\n    expect(disjointSet.inSameSet('A', 'I')).toBe(false);\n    expect(disjointSet.inSameSet('E', 'I')).toBe(true);\n\n    disjointSet.union('I', 'C');\n\n    expect(disjointSet.find('I')).toBe('E');\n    expect(disjointSet.inSameSet('A', 'I')).toBe(true);\n  });\n\n  it('should union smaller set with bigger one making bigger one to be new root', () => {\n    const disjointSet = new DisjointSet();\n\n    disjointSet\n      .makeSet('A')\n      .makeSet('B')\n      .makeSet('C')\n      .union('B', 'C')\n      .union('A', 'C');\n\n    expect(disjointSet.find('A')).toBe('B');\n  });\n\n  it('should do basic manipulations on disjoint set with custom key extractor', () => {\n    const keyExtractor = (value) => value.key;\n\n    const disjointSet = new DisjointSet(keyExtractor);\n\n    const itemA = { key: 'A', value: 1 };\n    const itemB = { key: 'B', value: 2 };\n    const itemC = { key: 'C', value: 3 };\n\n    expect(disjointSet.find(itemA)).toBeNull();\n    expect(disjointSet.find(itemB)).toBeNull();\n\n    disjointSet.makeSet(itemA);\n\n    expect(disjointSet.find(itemA)).toBe('A');\n    expect(disjointSet.find(itemB)).toBeNull();\n\n    disjointSet.makeSet(itemB);\n\n    expect(disjointSet.find(itemA)).toBe('A');\n    expect(disjointSet.find(itemB)).toBe('B');\n\n    disjointSet.makeSet(itemC);\n\n    expect(disjointSet.inSameSet(itemA, itemB)).toBe(false);\n\n    disjointSet.union(itemA, itemB);\n\n    expect(disjointSet.find(itemA)).toBe('A');\n    expect(disjointSet.find(itemB)).toBe('A');\n    expect(disjointSet.inSameSet(itemA, itemB)).toBe(true);\n    expect(disjointSet.inSameSet(itemB, itemA)).toBe(true);\n    expect(disjointSet.inSameSet(itemA, itemC)).toBe(false);\n\n    disjointSet.union(itemA, itemC);\n\n    expect(disjointSet.find(itemA)).toBe('A');\n    expect(disjointSet.find(itemB)).toBe('A');\n    expect(disjointSet.find(itemC)).toBe('A');\n\n    expect(disjointSet.inSameSet(itemA, itemB)).toBe(true);\n    expect(disjointSet.inSameSet(itemB, itemC)).toBe(true);\n    expect(disjointSet.inSameSet(itemA, itemC)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/disjoint-set/__test__/DisjointSetAdhoc.test.js",
    "content": "import DisjointSetAdhoc from '../DisjointSetAdhoc';\n\ndescribe('DisjointSetAdhoc', () => {\n  it('should create unions and find connected elements', () => {\n    const set = new DisjointSetAdhoc(10);\n\n    // 1-2-5-6-7 3-8-9 4\n    set.union(1, 2);\n    set.union(2, 5);\n    set.union(5, 6);\n    set.union(6, 7);\n\n    set.union(3, 8);\n    set.union(8, 9);\n\n    expect(set.connected(1, 5)).toBe(true);\n    expect(set.connected(5, 7)).toBe(true);\n    expect(set.connected(3, 8)).toBe(true);\n\n    expect(set.connected(4, 9)).toBe(false);\n    expect(set.connected(4, 7)).toBe(false);\n\n    // 1-2-5-6-7 3-8-9-4\n    set.union(9, 4);\n\n    expect(set.connected(4, 9)).toBe(true);\n    expect(set.connected(4, 3)).toBe(true);\n    expect(set.connected(8, 4)).toBe(true);\n\n    expect(set.connected(8, 7)).toBe(false);\n    expect(set.connected(2, 3)).toBe(false);\n  });\n\n  it('should keep the height of the tree small', () => {\n    const set = new DisjointSetAdhoc(10);\n\n    // 1-2-6-7-9 1 3 4 5\n    set.union(7, 6);\n    set.union(1, 2);\n    set.union(2, 6);\n    set.union(1, 7);\n    set.union(9, 1);\n\n    expect(set.connected(1, 7)).toBe(true);\n    expect(set.connected(6, 9)).toBe(true);\n    expect(set.connected(4, 9)).toBe(false);\n\n    expect(Math.max(...set.heights)).toBe(3);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/disjoint-set/__test__/DisjointSetItem.test.js",
    "content": "import DisjointSetItem from '../DisjointSetItem';\n\ndescribe('DisjointSetItem', () => {\n  it('should do basic manipulation with disjoint set item', () => {\n    const itemA = new DisjointSetItem('A');\n    const itemB = new DisjointSetItem('B');\n    const itemC = new DisjointSetItem('C');\n    const itemD = new DisjointSetItem('D');\n\n    expect(itemA.getRank()).toBe(0);\n    expect(itemA.getChildren()).toEqual([]);\n    expect(itemA.getKey()).toBe('A');\n    expect(itemA.getRoot()).toEqual(itemA);\n    expect(itemA.isRoot()).toBe(true);\n    expect(itemB.isRoot()).toBe(true);\n\n    itemA.addChild(itemB);\n    itemD.setParent(itemC);\n\n    expect(itemA.getRank()).toBe(1);\n    expect(itemC.getRank()).toBe(1);\n\n    expect(itemB.getRank()).toBe(0);\n    expect(itemD.getRank()).toBe(0);\n\n    expect(itemA.getChildren().length).toBe(1);\n    expect(itemC.getChildren().length).toBe(1);\n\n    expect(itemA.getChildren()[0]).toEqual(itemB);\n    expect(itemC.getChildren()[0]).toEqual(itemD);\n\n    expect(itemB.getChildren().length).toBe(0);\n    expect(itemD.getChildren().length).toBe(0);\n\n    expect(itemA.getRoot()).toEqual(itemA);\n    expect(itemB.getRoot()).toEqual(itemA);\n\n    expect(itemC.getRoot()).toEqual(itemC);\n    expect(itemD.getRoot()).toEqual(itemC);\n\n    expect(itemA.isRoot()).toBe(true);\n    expect(itemB.isRoot()).toBe(false);\n    expect(itemC.isRoot()).toBe(true);\n    expect(itemD.isRoot()).toBe(false);\n\n    itemA.addChild(itemC);\n\n    expect(itemA.isRoot()).toBe(true);\n    expect(itemB.isRoot()).toBe(false);\n    expect(itemC.isRoot()).toBe(false);\n    expect(itemD.isRoot()).toBe(false);\n\n    expect(itemA.getRank()).toEqual(3);\n    expect(itemB.getRank()).toEqual(0);\n    expect(itemC.getRank()).toEqual(1);\n  });\n\n  it('should do basic manipulation with disjoint set item with custom key extractor', () => {\n    const keyExtractor = (value) => {\n      return value.key;\n    };\n\n    const itemA = new DisjointSetItem({ key: 'A', value: 1 }, keyExtractor);\n    const itemB = new DisjointSetItem({ key: 'B', value: 2 }, keyExtractor);\n    const itemC = new DisjointSetItem({ key: 'C', value: 3 }, keyExtractor);\n    const itemD = new DisjointSetItem({ key: 'D', value: 4 }, keyExtractor);\n\n    expect(itemA.getRank()).toBe(0);\n    expect(itemA.getChildren()).toEqual([]);\n    expect(itemA.getKey()).toBe('A');\n    expect(itemA.getRoot()).toEqual(itemA);\n    expect(itemA.isRoot()).toBe(true);\n    expect(itemB.isRoot()).toBe(true);\n\n    itemA.addChild(itemB);\n    itemD.setParent(itemC);\n\n    expect(itemA.getRank()).toBe(1);\n    expect(itemC.getRank()).toBe(1);\n\n    expect(itemB.getRank()).toBe(0);\n    expect(itemD.getRank()).toBe(0);\n\n    expect(itemA.getChildren().length).toBe(1);\n    expect(itemC.getChildren().length).toBe(1);\n\n    expect(itemA.getChildren()[0]).toEqual(itemB);\n    expect(itemC.getChildren()[0]).toEqual(itemD);\n\n    expect(itemB.getChildren().length).toBe(0);\n    expect(itemD.getChildren().length).toBe(0);\n\n    expect(itemA.getRoot()).toEqual(itemA);\n    expect(itemB.getRoot()).toEqual(itemA);\n\n    expect(itemC.getRoot()).toEqual(itemC);\n    expect(itemD.getRoot()).toEqual(itemC);\n\n    expect(itemA.isRoot()).toBe(true);\n    expect(itemB.isRoot()).toBe(false);\n    expect(itemC.isRoot()).toBe(true);\n    expect(itemD.isRoot()).toBe(false);\n\n    itemA.addChild(itemC);\n\n    expect(itemA.isRoot()).toBe(true);\n    expect(itemB.isRoot()).toBe(false);\n    expect(itemC.isRoot()).toBe(false);\n    expect(itemD.isRoot()).toBe(false);\n\n    expect(itemA.getRank()).toEqual(3);\n    expect(itemB.getRank()).toEqual(0);\n    expect(itemC.getRank()).toEqual(1);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/DoublyLinkedList.js",
    "content": "import DoublyLinkedListNode from './DoublyLinkedListNode';\nimport Comparator from '../../utils/comparator/Comparator';\n\nexport default class DoublyLinkedList {\n  /**\n   * @param {Function} [comparatorFunction]\n   */\n  constructor(comparatorFunction) {\n    /** @var DoublyLinkedListNode */\n    this.head = null;\n\n    /** @var DoublyLinkedListNode */\n    this.tail = null;\n\n    this.compare = new Comparator(comparatorFunction);\n  }\n\n  /**\n   * @param {*} value\n   * @return {DoublyLinkedList}\n   */\n  prepend(value) {\n    // Make new node to be a head.\n    const newNode = new DoublyLinkedListNode(value, this.head);\n\n    // If there is head, then it won't be head anymore.\n    // Therefore, make its previous reference to be new node (new head).\n    // Then mark the new node as head.\n    if (this.head) {\n      this.head.previous = newNode;\n    }\n    this.head = newNode;\n\n    // If there is no tail yet let's make new node a tail.\n    if (!this.tail) {\n      this.tail = newNode;\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {*} value\n   * @return {DoublyLinkedList}\n   */\n  append(value) {\n    const newNode = new DoublyLinkedListNode(value);\n\n    // If there is no head yet let's make new node a head.\n    if (!this.head) {\n      this.head = newNode;\n      this.tail = newNode;\n\n      return this;\n    }\n\n    // Attach new node to the end of linked list.\n    this.tail.next = newNode;\n\n    // Attach current tail to the new node's previous reference.\n    newNode.previous = this.tail;\n\n    // Set new node to be the tail of linked list.\n    this.tail = newNode;\n\n    return this;\n  }\n\n  /**\n   * @param {*} value\n   * @return {DoublyLinkedListNode}\n   */\n  delete(value) {\n    if (!this.head) {\n      return null;\n    }\n\n    let deletedNode = null;\n    let currentNode = this.head;\n\n    while (currentNode) {\n      if (this.compare.equal(currentNode.value, value)) {\n        deletedNode = currentNode;\n\n        if (deletedNode === this.head) {\n          // If HEAD is going to be deleted...\n\n          // Set head to second node, which will become new head.\n          this.head = deletedNode.next;\n\n          // Set new head's previous to null.\n          if (this.head) {\n            this.head.previous = null;\n          }\n\n          // If all the nodes in list has same value that is passed as argument\n          // then all nodes will get deleted, therefore tail needs to be updated.\n          if (deletedNode === this.tail) {\n            this.tail = null;\n          }\n        } else if (deletedNode === this.tail) {\n          // If TAIL is going to be deleted...\n\n          // Set tail to second last node, which will become new tail.\n          this.tail = deletedNode.previous;\n          this.tail.next = null;\n        } else {\n          // If MIDDLE node is going to be deleted...\n          const previousNode = deletedNode.previous;\n          const nextNode = deletedNode.next;\n\n          previousNode.next = nextNode;\n          nextNode.previous = previousNode;\n        }\n      }\n\n      currentNode = currentNode.next;\n    }\n\n    return deletedNode;\n  }\n\n  /**\n   * @param {Object} findParams\n   * @param {*} findParams.value\n   * @param {function} [findParams.callback]\n   * @return {DoublyLinkedListNode}\n   */\n  find({ value = undefined, callback = undefined }) {\n    if (!this.head) {\n      return null;\n    }\n\n    let currentNode = this.head;\n\n    while (currentNode) {\n      // If callback is specified then try to find node by callback.\n      if (callback && callback(currentNode.value)) {\n        return currentNode;\n      }\n\n      // If value is specified then try to compare by value..\n      if (value !== undefined && this.compare.equal(currentNode.value, value)) {\n        return currentNode;\n      }\n\n      currentNode = currentNode.next;\n    }\n\n    return null;\n  }\n\n  /**\n   * @return {DoublyLinkedListNode}\n   */\n  deleteTail() {\n    if (!this.tail) {\n      // No tail to delete.\n      return null;\n    }\n\n    if (this.head === this.tail) {\n      // There is only one node in linked list.\n      const deletedTail = this.tail;\n      this.head = null;\n      this.tail = null;\n\n      return deletedTail;\n    }\n\n    // If there are many nodes in linked list...\n    const deletedTail = this.tail;\n\n    this.tail = this.tail.previous;\n    this.tail.next = null;\n\n    return deletedTail;\n  }\n\n  /**\n   * @return {DoublyLinkedListNode}\n   */\n  deleteHead() {\n    if (!this.head) {\n      return null;\n    }\n\n    const deletedHead = this.head;\n\n    if (this.head.next) {\n      this.head = this.head.next;\n      this.head.previous = null;\n    } else {\n      this.head = null;\n      this.tail = null;\n    }\n\n    return deletedHead;\n  }\n\n  /**\n   * @return {DoublyLinkedListNode[]}\n   */\n  toArray() {\n    const nodes = [];\n\n    let currentNode = this.head;\n    while (currentNode) {\n      nodes.push(currentNode);\n      currentNode = currentNode.next;\n    }\n\n    return nodes;\n  }\n\n  /**\n   * @param {*[]} values - Array of values that need to be converted to linked list.\n   * @return {DoublyLinkedList}\n   */\n  fromArray(values) {\n    values.forEach((value) => this.append(value));\n\n    return this;\n  }\n\n  /**\n   * @param {function} [callback]\n   * @return {string}\n   */\n  toString(callback) {\n    return this.toArray().map((node) => node.toString(callback)).toString();\n  }\n\n  /**\n   * Reverse a linked list.\n   * @returns {DoublyLinkedList}\n   */\n  reverse() {\n    let currNode = this.head;\n    let prevNode = null;\n    let nextNode = null;\n\n    while (currNode) {\n      // Store next node.\n      nextNode = currNode.next;\n      prevNode = currNode.previous;\n\n      // Change next node of the current node so it would link to previous node.\n      currNode.next = prevNode;\n      currNode.previous = nextNode;\n\n      // Move prevNode and currNode nodes one step forward.\n      prevNode = currNode;\n      currNode = nextNode;\n    }\n\n    // Reset head and tail.\n    this.tail = this.head;\n    this.head = prevNode;\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/DoublyLinkedListNode.js",
    "content": "export default class DoublyLinkedListNode {\n  constructor(value, next = null, previous = null) {\n    this.value = value;\n    this.next = next;\n    this.previous = previous;\n  }\n\n  toString(callback) {\n    return callback ? callback(this.value) : `${this.value}`;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.es-ES.md",
    "content": "# Lista doblemente enlazada\n\n_Lea esto en otros idiomas:_\n[_Русский_](README.ru-RU.md),\n[_简体中文_](README.zh-CN.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md)\n[_한국어_](README.ko-KR.md)\n\nEn 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.\n\n![Lista doblemente enlazada](./images/doubly-linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nLos 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.\n\n## Pseudocódigo para operaciones básicas\n\n### Insertar\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### Eliminar\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true; otherwise false\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n != ø and value !== n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n != ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Recorrido Inverso\n\n```text\nReverseTraversal(tail)\n  Pre: tail is the node of the list to traverse\n  Post: the list has been traversed in reverse order\n  n ← tail\n  while n != ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## Complejidades\n\n## Complejidad del Tiempo\n\n| Acceso | Búsqueda | Inserción | Eliminación |\n| :----: | :------: | :-------: | :---------: |\n|  O(n)  |   O(n)   |   O(1)    |    O(n)     |\n\n### Complejidad del Espacio\n\nO(n)\n\n## Referencias\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)\n- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.ja-JP.md",
    "content": "# 双方向リスト\n\nコンピュータサイエンスにおいて、**双方向リスト**はノードと呼ばれる一連のリンクレコードからなる連結データ構造です。各ノードはリンクと呼ばれる2つのフィールドを持っていて、これらは一連のノード内における前のノードと次のノードを参照しています。最初のノードの前のリンクと最後のノードの次のリンクはある種の終端を示していて、一般的にはダミーノードやnullが格納され、リストのトラバースを容易に行えるようにしています。もしダミーノードが1つしかない場合、リストはその1つのノードを介して循環的にリンクされます。これは、それぞれ逆の順番の単方向のリンクリストが2つあるものとして考えることができます。\n\n![Doubly Linked List](./images/doubly-linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n2つのリンクにより、リストをどちらの方向にもトラバースすることができます。双方向リストはノードの追加や削除の際に、片方向リンクリストと比べてより多くのリンクを変更する必要があります。しかし、その操作は簡単で、より効率的な(最初のノード以外の場合)可能性があります。前のノードのリンクを更新する際に前のノードを保持したり、前のノードを見つけるためにリストをトラバースする必要がありません。\n\n## 基本操作の擬似コード\n\n### 挿入\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### 削除\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true; otherwise false\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n = ø and value !== n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n = ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### 逆トラバース\n\n```text\nReverseTraversal(tail)\n  Pre: tail is the node of the list to traverse\n  Post: the list has been traversed in reverse order\n  n ← tail\n  while n = ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## 計算量\n\n## 時間計算量\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(n)      |\n\n### 空間計算量\n\nO(n)\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)\n- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.ko-KR.md",
    "content": "# Doubly Linked List\n\n_Read this in other languages:_\n[_Русский_](README.ru-RU.md),\n[_简体中文_](README.zh-CN.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md)\n\n컴퓨터공학에서 **이중 연결 리스트**는 순차적으로 링크된 노드라는 레코드 세트로 구성된 링크된 데이터 구조입니다.\n각 노드에는 링크라고 하는 두 개의 필드가 있으며, 노드 순서에서 이전 노드와 다음 노드에 대한 참조를 가집니다.\n시작 및 종료 노드의 이전 및 다음 링크는 각각 리스트의 순회를 용이하게 하기 위해서 일종의 종결자 (일반적으로 센티넬노드 또는 null)를 나타냅니다.\n센티넬 노드가 하나만 있으면, 목록이 센티넬 노드를 통해서 원형으로 연결됩니다.\n동일한 데이터 항목으로 구성되어 있지만, 반대 순서로 두 개의 단일 연결 리스트로 개념화 할 수 있습니다.\n\n![이중 연결 리스트](./images/doubly-linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n두 개의 노드 링크를 사용하면 어느 방향으로든 리스트를 순회할 수 있습니다.\n이중 연결 리스트에서 노드를 추가하거나 제거하려면, 단일 연결 리스트에서 동일한 작업보다 더 많은 링크를 변경해야 하지만, 첫 번째 노드 이외의 노드인 경우 작업을 추적할 필요가 없으므로 작업이 더 단순해져 잠재적으로 더 효율적입니다.\n리스트 순회 중 이전 노드 또는 링크를 수정할 수 있도록 이전 노드를 찾기 위해 리스트를 순회할 필요가 없습니다.\n\n## 기본 동작을 위한 Pseudocode\n\n### 삽입\n\n```text\nAdd(value)\n  Pre: value는 리스트에 추가하고자 하는 값\n  Post: value는 목록의 끝에 배치됨\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### 삭제\n\n```text\nRemove(head, value)\n  Pre: head는 리스트의 앞단에 위치\n       value는 리스트에서 제거하고자 하는 값\n  Post: value가 리스트에서 제거되면 true; 아니라면 false;\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n = ø and value !== n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n = ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### 역순회\n\n```text\nReverseTraversal(tail)\n  Pre: tail은 리스트에서 순회하고자 하는 노드\n  Post: 리스트가 역순으로 순회됨\n  n ← tail\n  while n = ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## 복잡도\n\n## 시간 복잡도\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(n)      |\n\n### 공간 복잡도\n\nO(n)\n\n## 참고\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)\n- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.md",
    "content": "# Doubly Linked List\n\n_Read this in other languages:_\n[_Русский_](README.ru-RU.md),\n[_简体中文_](README.zh-CN.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Español_](README.es-ES.md),\n[_Українська_](README.uk-UA.md)\n\nIn computer science, a **doubly linked list** is a linked data structure that\nconsists of a set of sequentially linked records called nodes. Each node contains\ntwo fields, called links, that are references to the previous and to the next\nnode in the sequence of nodes. The beginning and ending nodes' previous and next\nlinks, respectively, point to some kind of terminator, typically a sentinel\nnode or null, to facilitate the traversal of the list. If there is only one\nsentinel node, then the list is circularly linked via the sentinel node. It can\nbe conceptualized as two singly linked lists formed from the same data items,\nbut in opposite sequential orders.\n\n![Doubly Linked List](./images/doubly-linked-list.jpeg)\n\n_Made with [okso.app](https://okso.app)_\n\nThe two node links allow traversal of the list in either direction. While adding\nor removing a node in a doubly linked list requires changing more links than the\nsame operations on a singly linked list, the operations are simpler and\npotentially more efficient (for nodes other than first nodes) because there\nis no need to keep track of the previous node during traversal or no need\nto traverse the list to find the previous node, so that its link can be modified.\n\n## Pseudocode for Basic Operations\n\n### Insert\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### Delete\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true; otherwise false\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n != ø and value !== n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n != ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Reverse Traversal\n\n```text\nReverseTraversal(tail)\n  Pre: tail is the node of the list to traverse\n  Post: the list has been traversed in reverse order\n  n ← tail\n  while n != ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## Complexities\n\n## Time Complexity\n\n| Access | Search | Insertion | Deletion |\n| :----: | :----: | :-------: | :------: |\n|  O(n)  |  O(n)  |   O(1)    |   O(n)   |\n\n### Space Complexity\n\nO(n)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)\n- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.pt-BR.md",
    "content": "# Lista Duplamente Ligada (Doubly Linked List)\n\nNa ciência da computação, uma **lista duplamente conectada** é uma estrutura\nde dados vinculada que se consistem em um conjunto de registros\nsequencialmente vinculados chamados de nós (nodes). Em cada nó contém dois\ncampos, chamados de ligações, que são referenciados ao nó anterior e posterior\nde uma sequência de nós. O começo e o fim dos nós anteriormente e posteriormente\nligados, respectiviamente, apontam para algum tipo de terminação, normalmente\num nó sentinela ou nulo, para facilitar a travessia da lista. Se existe\nsomente um nó sentinela, então a lista é ligada circularmente através do nó\nsentinela. Ela pode ser conceitualizada como duas listas individualmente ligadas\ne formadas a partir dos mesmos itens, mas em ordem sequencial opostas.\n\n![Doubly Linked List](./images/doubly-linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nOs dois nós ligados permitem a travessia da lista em qualquer direção.\nEnquanto adicionar ou remover um nó de uma lista duplamente vinculada requer\nalterar mais ligações (conexões) do que em uma lista encadeada individualmente\n(singly linked list), as operações são mais simples e potencialmente mais\neficientes (para nós que não sejam nós iniciais) porque não há necessidade\nde manter um rastreamento do nó anterior durante a travessia ou não há\nnecessidade de percorrer a lista para encontrar o nó anterior, para que\nentão sua ligação/conexão possa ser modificada.\n\n## Pseudocódigo para Operações Básicas\n\n### Inserir\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### Remoção\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true; otherwise false\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n = ø and value !== n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n = ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Travessia reversa\n\n```text\nReverseTraversal(tail)\n  Pre: tail is the node of the list to traverse\n  Post: the list has been traversed in reverse order\n  n ← tail\n  while n = ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## Complexidades\n\n## Complexidade de Tempo\n\n| Acesso    | Pesquisa    | Inserção | Remoção  |\n| :-------: | :---------: | :------: | :------: |\n| O(n)      | O(n)        | O(1)     | O(n)     |\n\n### Complexidade de Espaço\n\nO(n)\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)\n- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.ru-RU.md",
    "content": "# Двусвязный список\n\n**Двусвязный список** — связная структура данных в информатике, состоящая из набора\nпоследовательно связанных записей, называемых узлами. Каждый узел содержит два поля,\nназываемых ссылками, которые указывают на предыдущий и последующий элементы в\nпоследовательности узлов. Ссылка на предыдущий элемент корневого узла и ссылка на\nпоследующий элемент последнего узла указывают на некого рода прерыватель, обычно\nсторожевой узел или null, для облегчения обхода списка. Если в списке только один\nсторожевой узел, тогда список циклически связан через него.\nДвусвязный список можно представить, как два связных списка, которые образованы из\nодних и тех же данных, но расположенных в противоположном порядке.\n\n![Двусвязный список](./images/doubly-linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nДве ссылки позволяют обходить список в обоих направлениях. Добавление и\nудаление узла в двусвязном списке требует изменения большего количества ссылок,\nчем аналогичные операции в связном списке. Однако данные операции проще и потенциально\nболее эффективны (для некорневых узлов) - при обходе не нужно следить за предыдущим\nузлом или повторно обходить список в поиске предыдущего узла, плюс его ссылка\nможет быть изменена.\n\n## Псевдокод основных операций\n\n### Вставка\n\n```text\nAdd(value)\n  Pre: value - добавляемое значение\n  Post: value помещено в конец списка\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### Удаление\n\n```text\nRemove(head, value)\n  Pre: head - первый узел в списке\n       value - значение, которое следует удалить\n  Post: true - value удалено из списка, иначе false\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n = ø and value = n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n = ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Обратный обход\n\n```text\nReverseTraversal(tail)\n  Pre: tail - конечный элемент обходимого списка\n  Post: элементы списка пройдены в обратном порядке\n  n ← tail\n  while n = ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## Сложность\n\n## Временная сложность\n\n| Чтение    | Поиск     | Вставка   | Удаление  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(n)      |\n\n### Пространственная сложность\n\nO(n)\n\n## Ссылки\n\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))\n- [YouTube](https://www.youtube.com/watch?v=lQ-lPjbb9Ew)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.uk-UA.md",
    "content": "# Двобічно зв'язаний список\n\n**Двобічно зв'язаний список** — зв'язкова структура даних в інформатиці, що складається з набору\nпослідовно пов'язаних записів, званих вузлами. Кожен вузол містить два поля,\nзваних посиланнями, які вказують на попередній і наступний елементи\nпослідовність вузлів. Посилання на попередній елемент кореневого вузла та посилання на\nНаступний елемент останнього вузла вказують на деякого роду переривник, зазвичай\nсторожовий вузол або null для полегшення обходу списку. Якщо у списку лише один\nсторожовий вузол, тоді перелік циклічно пов'язаний через нього.\nДвобічно зв'язаний список можна уявити, як два зв'язкові списки, які утворені з\nодних і тих самих даних, але розташованих у протилежному порядку.\n\n![Двобічно зв'язаний список](./images/doubly-linked-list.jpeg)\n\n_Made with [okso.app](https://okso.app)_\n\nДва посилання дозволяють обходити список в обох напрямках. Додавання та\nвидалення вузла у двозв'язному списку вимагає зміни більшої кількості посилань,\nніж аналогічні операції у зв'язковому списку. Однак дані операції простіше та потенційно\nбільш ефективні (для некореневих вузлів) – при обході не потрібно стежити за попереднім\nвузлом або повторно обходити список у пошуку попереднього вузла, плюс його посилання\nможе бути змінено.\n\n## Псевдокод основних операцій\n\n### Вставка\n\n```text\nAdd(value)\n  Pre: value - значення, що додається\n  Post: value поміщено в кінець списку\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### Видалення\n\n```text\nRemove(head, value)\n  Pre: head - перший вузол у списку\n       value - значення, яке слід видалити\n  Post: true - value видалено зі списку, інакше false\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n = ø and value = n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n = ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Зворотний обхід\n\n```text\nReverseTraversal(tail)\n  Pre: tail - кінцевий елемент обхідного списку\n  Post: елементи списку пройдено у зворотному порядку\n  n ← tail\n  while n = ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## Складність\n\n## Часова складність\n\n| Читання | Пошук | Вставка | Видалення |\n| :-----: | :---: | :-----: | :-------: |\n|  O(n)   | O(n)  |  O(1)   |   O(n)    |\n\n### Просторова складність\n\nO(n)\n\n## Посилання\n\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.)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/README.zh-CN.md",
    "content": "# 双向链表\n\n在计算机科学中, 一个 **双向链表(doubly linked list)** 是由一组称为节点的顺序链接记录组成的链接数据结构。每个节点包含两个字段，称为链接，它们是对节点序列中上一个节点和下一个节点的引用。开始节点和结束节点的上一个链接和下一个链接分别指向某种终止节点，通常是前哨节点或null，以方便遍历列表。如果只有一个前哨节点，则列表通过前哨节点循环链接。它可以被概念化为两个由相同数据项组成的单链表，但顺序相反。\n\n![Doubly Linked List](./images/doubly-linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n两个节点链接允许在任一方向上遍历列表。\n\n在双向链表中进行添加或者删除节点时,需做的链接更改要比单向链表复杂得多。这种操作在单向链表中更简单高效,因为不需要关注一个节点（除第一个和最后一个节点以外的节点）的两个链接,而只需要关注一个链接即可。\n\n\n\n## 基础操作的伪代码\n\n### 插入\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head != ø\n    head ← n\n    tail ← n\n  else\n    n.previous ← tail\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n### 删除\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true; otherwise false\n  if head = ø\n    return false\n  end if\n  if value = head.value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n      head.previous ← ø\n    end if\n    return true\n  end if\n  n ← head.next\n  while n != ø and value !== n.value\n    n ← n.next\n  end while\n  if n = tail\n    tail ← tail.previous\n    tail.next ← ø\n    return true\n  else if n != ø\n    n.previous.next ← n.next\n    n.next.previous ← n.previous\n    return true\n  end if\n  return false\nend Remove\n```\n\n### 反向遍历\n\n```text\nReverseTraversal(tail)\n  Pre: tail is the node of the list to traverse\n  Post: the list has been traversed in reverse order\n  n ← tail\n  while n != ø\n    yield n.value\n    n ← n.previous\n  end while\nend Reverse Traversal\n```\n\n## 复杂度\n\n## 时间复杂度\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(1)      |\n\n### 空间复杂度\n\nO(n)\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)\n- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/__test__/DoublyLinkedList.test.js",
    "content": "import DoublyLinkedList from '../DoublyLinkedList';\n\ndescribe('DoublyLinkedList', () => {\n  it('should create empty linked list', () => {\n    const linkedList = new DoublyLinkedList();\n    expect(linkedList.toString()).toBe('');\n  });\n\n  it('should append node to linked list', () => {\n    const linkedList = new DoublyLinkedList();\n\n    expect(linkedList.head).toBeNull();\n    expect(linkedList.tail).toBeNull();\n\n    linkedList.append(1);\n    linkedList.append(2);\n\n    expect(linkedList.head.next.value).toBe(2);\n    expect(linkedList.tail.previous.value).toBe(1);\n    expect(linkedList.toString()).toBe('1,2');\n  });\n\n  it('should prepend node to linked list', () => {\n    const linkedList = new DoublyLinkedList();\n\n    linkedList.prepend(2);\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    linkedList.append(1);\n    linkedList.prepend(3);\n\n    expect(linkedList.head.next.next.previous).toBe(linkedList.head.next);\n    expect(linkedList.tail.previous.next).toBe(linkedList.tail);\n    expect(linkedList.tail.previous.value).toBe(2);\n    expect(linkedList.toString()).toBe('3,2,1');\n  });\n\n  it('should create linked list from array', () => {\n    const linkedList = new DoublyLinkedList();\n    linkedList.fromArray([1, 1, 2, 3, 3, 3, 4, 5]);\n\n    expect(linkedList.toString()).toBe('1,1,2,3,3,3,4,5');\n  });\n\n  it('should delete node by value from linked list', () => {\n    const linkedList = new DoublyLinkedList();\n\n    expect(linkedList.delete(5)).toBeNull();\n\n    linkedList.append(1);\n    linkedList.append(1);\n    linkedList.append(2);\n    linkedList.append(3);\n    linkedList.append(3);\n    linkedList.append(3);\n    linkedList.append(4);\n    linkedList.append(5);\n\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('5');\n\n    const deletedNode = linkedList.delete(3);\n    expect(deletedNode.value).toBe(3);\n    expect(linkedList.tail.previous.previous.value).toBe(2);\n    expect(linkedList.toString()).toBe('1,1,2,4,5');\n\n    linkedList.delete(3);\n    expect(linkedList.toString()).toBe('1,1,2,4,5');\n\n    linkedList.delete(1);\n    expect(linkedList.toString()).toBe('2,4,5');\n\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.head.next.next).toBe(linkedList.tail);\n    expect(linkedList.tail.previous.previous).toBe(linkedList.head);\n    expect(linkedList.tail.toString()).toBe('5');\n\n    linkedList.delete(5);\n    expect(linkedList.toString()).toBe('2,4');\n\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('4');\n\n    linkedList.delete(4);\n    expect(linkedList.toString()).toBe('2');\n\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('2');\n    expect(linkedList.head).toBe(linkedList.tail);\n\n    linkedList.delete(2);\n    expect(linkedList.toString()).toBe('');\n  });\n\n  it('should delete linked list tail', () => {\n    const linkedList = new DoublyLinkedList();\n\n    expect(linkedList.deleteTail()).toBeNull();\n\n    linkedList.append(1);\n    linkedList.append(2);\n    linkedList.append(3);\n\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('3');\n\n    const deletedNode1 = linkedList.deleteTail();\n\n    expect(deletedNode1.value).toBe(3);\n    expect(linkedList.toString()).toBe('1,2');\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    const deletedNode2 = linkedList.deleteTail();\n\n    expect(deletedNode2.value).toBe(2);\n    expect(linkedList.toString()).toBe('1');\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('1');\n\n    const deletedNode3 = linkedList.deleteTail();\n\n    expect(deletedNode3.value).toBe(1);\n    expect(linkedList.toString()).toBe('');\n    expect(linkedList.head).toBeNull();\n    expect(linkedList.tail).toBeNull();\n  });\n\n  it('should delete linked list head', () => {\n    const linkedList = new DoublyLinkedList();\n\n    expect(linkedList.deleteHead()).toBeNull();\n\n    linkedList.append(1);\n    linkedList.append(2);\n\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    const deletedNode1 = linkedList.deleteHead();\n\n    expect(deletedNode1.value).toBe(1);\n    expect(linkedList.head.previous).toBeNull();\n    expect(linkedList.toString()).toBe('2');\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    const deletedNode2 = linkedList.deleteHead();\n\n    expect(deletedNode2.value).toBe(2);\n    expect(linkedList.toString()).toBe('');\n    expect(linkedList.head).toBeNull();\n    expect(linkedList.tail).toBeNull();\n  });\n\n  it('should be possible to store objects in the list and to print them out', () => {\n    const linkedList = new DoublyLinkedList();\n\n    const nodeValue1 = { value: 1, key: 'key1' };\n    const nodeValue2 = { value: 2, key: 'key2' };\n\n    linkedList\n      .append(nodeValue1)\n      .prepend(nodeValue2);\n\n    const nodeStringifier = (value) => `${value.key}:${value.value}`;\n\n    expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1');\n  });\n\n  it('should find node by value', () => {\n    const linkedList = new DoublyLinkedList();\n\n    expect(linkedList.find({ value: 5 })).toBeNull();\n\n    linkedList.append(1);\n    expect(linkedList.find({ value: 1 })).toBeDefined();\n\n    linkedList\n      .append(2)\n      .append(3);\n\n    const node = linkedList.find({ value: 2 });\n\n    expect(node.value).toBe(2);\n    expect(linkedList.find({ value: 5 })).toBeNull();\n  });\n\n  it('should find node by callback', () => {\n    const linkedList = new DoublyLinkedList();\n\n    linkedList\n      .append({ value: 1, key: 'test1' })\n      .append({ value: 2, key: 'test2' })\n      .append({ value: 3, key: 'test3' });\n\n    const node = linkedList.find({ callback: (value) => value.key === 'test2' });\n\n    expect(node).toBeDefined();\n    expect(node.value.value).toBe(2);\n    expect(node.value.key).toBe('test2');\n    expect(linkedList.find({ callback: (value) => value.key === 'test5' })).toBeNull();\n  });\n\n  it('should find node by means of custom compare function', () => {\n    const comparatorFunction = (a, b) => {\n      if (a.customValue === b.customValue) {\n        return 0;\n      }\n\n      return a.customValue < b.customValue ? -1 : 1;\n    };\n\n    const linkedList = new DoublyLinkedList(comparatorFunction);\n\n    linkedList\n      .append({ value: 1, customValue: 'test1' })\n      .append({ value: 2, customValue: 'test2' })\n      .append({ value: 3, customValue: 'test3' });\n\n    const node = linkedList.find({\n      value: { value: 2, customValue: 'test2' },\n    });\n\n    expect(node).toBeDefined();\n    expect(node.value.value).toBe(2);\n    expect(node.value.customValue).toBe('test2');\n    expect(linkedList.find({ value: 2, customValue: 'test5' })).toBeNull();\n  });\n\n  it('should reverse linked list', () => {\n    const linkedList = new DoublyLinkedList();\n\n    // Add test values to linked list.\n    linkedList\n      .append(1)\n      .append(2)\n      .append(3)\n      .append(4);\n\n    expect(linkedList.toString()).toBe('1,2,3,4');\n    expect(linkedList.head.value).toBe(1);\n    expect(linkedList.tail.value).toBe(4);\n\n    // Reverse linked list.\n    linkedList.reverse();\n\n    expect(linkedList.toString()).toBe('4,3,2,1');\n\n    expect(linkedList.head.previous).toBeNull();\n    expect(linkedList.head.value).toBe(4);\n    expect(linkedList.head.next.value).toBe(3);\n    expect(linkedList.head.next.next.value).toBe(2);\n    expect(linkedList.head.next.next.next.value).toBe(1);\n\n    expect(linkedList.tail.next).toBeNull();\n    expect(linkedList.tail.value).toBe(1);\n    expect(linkedList.tail.previous.value).toBe(2);\n    expect(linkedList.tail.previous.previous.value).toBe(3);\n    expect(linkedList.tail.previous.previous.previous.value).toBe(4);\n\n    // Reverse linked list back to initial state.\n    linkedList.reverse();\n\n    expect(linkedList.toString()).toBe('1,2,3,4');\n\n    expect(linkedList.head.previous).toBeNull();\n    expect(linkedList.head.value).toBe(1);\n    expect(linkedList.head.next.value).toBe(2);\n    expect(linkedList.head.next.next.value).toBe(3);\n    expect(linkedList.head.next.next.next.value).toBe(4);\n\n    expect(linkedList.tail.next).toBeNull();\n    expect(linkedList.tail.value).toBe(4);\n    expect(linkedList.tail.previous.value).toBe(3);\n    expect(linkedList.tail.previous.previous.value).toBe(2);\n    expect(linkedList.tail.previous.previous.previous.value).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/doubly-linked-list/__test__/DoublyLinkedListNode.test.js",
    "content": "import DoublyLinkedListNode from '../DoublyLinkedListNode';\n\ndescribe('DoublyLinkedListNode', () => {\n  it('should create list node with value', () => {\n    const node = new DoublyLinkedListNode(1);\n\n    expect(node.value).toBe(1);\n    expect(node.next).toBeNull();\n    expect(node.previous).toBeNull();\n  });\n\n  it('should create list node with object as a value', () => {\n    const nodeValue = { value: 1, key: 'test' };\n    const node = new DoublyLinkedListNode(nodeValue);\n\n    expect(node.value.value).toBe(1);\n    expect(node.value.key).toBe('test');\n    expect(node.next).toBeNull();\n    expect(node.previous).toBeNull();\n  });\n\n  it('should link nodes together', () => {\n    const node2 = new DoublyLinkedListNode(2);\n    const node1 = new DoublyLinkedListNode(1, node2);\n    const node3 = new DoublyLinkedListNode(10, node1, node2);\n\n    expect(node1.next).toBeDefined();\n    expect(node1.previous).toBeNull();\n    expect(node2.next).toBeNull();\n    expect(node2.previous).toBeNull();\n    expect(node3.next).toBeDefined();\n    expect(node3.previous).toBeDefined();\n    expect(node1.value).toBe(1);\n    expect(node1.next.value).toBe(2);\n    expect(node3.next.value).toBe(1);\n    expect(node3.previous.value).toBe(2);\n  });\n\n  it('should convert node to string', () => {\n    const node = new DoublyLinkedListNode(1);\n\n    expect(node.toString()).toBe('1');\n\n    node.value = 'string value';\n    expect(node.toString()).toBe('string value');\n  });\n\n  it('should convert node to string with custom stringifier', () => {\n    const nodeValue = { value: 1, key: 'test' };\n    const node = new DoublyLinkedListNode(nodeValue);\n    const toStringCallback = (value) => `value: ${value.value}, key: ${value.key}`;\n\n    expect(node.toString(toStringCallback)).toBe('value: 1, key: test');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/graph/Graph.js",
    "content": "export default class Graph {\n  /**\n   * @param {boolean} isDirected\n   */\n  constructor(isDirected = false) {\n    this.vertices = {};\n    this.edges = {};\n    this.isDirected = isDirected;\n  }\n\n  /**\n   * @param {GraphVertex} newVertex\n   * @returns {Graph}\n   */\n  addVertex(newVertex) {\n    const key = newVertex.getKey();\n\n    if (this.vertices[key]) {\n      throw new Error('Vertex has already been added before');\n    }\n\n    this.vertices[key] = newVertex;\n\n    return this;\n  }\n\n  /**\n   * @param {string} vertexKey\n   * @returns GraphVertex\n   */\n  getVertexByKey(vertexKey) {\n    return this.vertices[vertexKey];\n  }\n\n  /**\n   * @param {GraphVertex} vertex\n   * @returns {GraphVertex[]}\n   */\n  getNeighbors(vertex) {\n    return vertex.getNeighbors();\n  }\n\n  /**\n   * @return {GraphVertex[]}\n   */\n  getAllVertices() {\n    return Object.values(this.vertices);\n  }\n\n  /**\n   * @return {GraphEdge[]}\n   */\n  getAllEdges() {\n    return Object.values(this.edges);\n  }\n\n  /**\n   * @param {GraphEdge} edge\n   * @returns {Graph}\n   */\n  addEdge(edge) {\n    // Try to find and end start vertices.\n    let startVertex = this.getVertexByKey(edge.startVertex.getKey());\n    let endVertex = this.getVertexByKey(edge.endVertex.getKey());\n\n    // Insert start vertex if it wasn't inserted.\n    if (!startVertex) {\n      this.addVertex(edge.startVertex);\n      startVertex = this.getVertexByKey(edge.startVertex.getKey());\n    }\n\n    // Insert end vertex if it wasn't inserted.\n    if (!endVertex) {\n      this.addVertex(edge.endVertex);\n      endVertex = this.getVertexByKey(edge.endVertex.getKey());\n    }\n\n    // Check if edge has been already added.\n    if (this.edges[edge.getKey()]) {\n      throw new Error('Edge has already been added before');\n    } else {\n      this.edges[edge.getKey()] = edge;\n    }\n\n    // Add edge to the vertices.\n    if (this.isDirected) {\n      // If graph IS directed then add the edge only to start vertex.\n      startVertex.addEdge(edge);\n    } else {\n      // If graph ISN'T directed then add the edge to both vertices.\n      startVertex.addEdge(edge);\n      endVertex.addEdge(edge);\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {GraphEdge} edge\n   */\n  deleteEdge(edge) {\n    // Delete edge from the list of edges.\n    if (this.edges[edge.getKey()]) {\n      delete this.edges[edge.getKey()];\n    } else {\n      throw new Error('Edge not found in graph');\n    }\n\n    // Try to find and end start vertices and delete edge from them.\n    const startVertex = this.getVertexByKey(edge.startVertex.getKey());\n    const endVertex = this.getVertexByKey(edge.endVertex.getKey());\n\n    startVertex.deleteEdge(edge);\n    endVertex.deleteEdge(edge);\n  }\n\n  /**\n   * @param {GraphVertex} startVertex\n   * @param {GraphVertex} endVertex\n   * @return {(GraphEdge|null)}\n   */\n  findEdge(startVertex, endVertex) {\n    const vertex = this.getVertexByKey(startVertex.getKey());\n\n    if (!vertex) {\n      return null;\n    }\n\n    return vertex.findEdge(endVertex);\n  }\n\n  /**\n   * @return {number}\n   */\n  getWeight() {\n    return this.getAllEdges().reduce((weight, graphEdge) => {\n      return weight + graphEdge.weight;\n    }, 0);\n  }\n\n  /**\n   * Reverse all the edges in directed graph.\n   * @return {Graph}\n   */\n  reverse() {\n    /** @param {GraphEdge} edge */\n    this.getAllEdges().forEach((edge) => {\n      // Delete straight edge from graph and from vertices.\n      this.deleteEdge(edge);\n\n      // Reverse the edge.\n      edge.reverse();\n\n      // Add reversed edge back to the graph and its vertices.\n      this.addEdge(edge);\n    });\n\n    return this;\n  }\n\n  /**\n   * @return {object}\n   */\n  getVerticesIndices() {\n    const verticesIndices = {};\n    this.getAllVertices().forEach((vertex, index) => {\n      verticesIndices[vertex.getKey()] = index;\n    });\n\n    return verticesIndices;\n  }\n\n  /**\n   * @return {*[][]}\n   */\n  getAdjacencyMatrix() {\n    const vertices = this.getAllVertices();\n    const verticesIndices = this.getVerticesIndices();\n\n    // Init matrix with infinities meaning that there is no ways of\n    // getting from one vertex to another yet.\n    const adjacencyMatrix = Array(vertices.length).fill(null).map(() => {\n      return Array(vertices.length).fill(Infinity);\n    });\n\n    // Fill the columns.\n    vertices.forEach((vertex, vertexIndex) => {\n      vertex.getNeighbors().forEach((neighbor) => {\n        const neighborIndex = verticesIndices[neighbor.getKey()];\n        adjacencyMatrix[vertexIndex][neighborIndex] = this.findEdge(vertex, neighbor).weight;\n      });\n    });\n\n    return adjacencyMatrix;\n  }\n\n  /**\n   * @return {string}\n   */\n  toString() {\n    return Object.keys(this.vertices).toString();\n  }\n}\n"
  },
  {
    "path": "src/data-structures/graph/GraphEdge.js",
    "content": "export default class GraphEdge {\n  /**\n   * @param {GraphVertex} startVertex\n   * @param {GraphVertex} endVertex\n   * @param {number} [weight=0]\n   * @param key\n   */\n  constructor(startVertex, endVertex, weight = 0, key = null) {\n    this.startVertex = startVertex;\n    this.endVertex = endVertex;\n    this.weight = weight;\n    this.key = key;\n  }\n\n  getKey() {\n    if (this.key) {\n      return this.key;\n    }\n\n    const startVertexKey = this.startVertex.getKey();\n    const endVertexKey = this.endVertex.getKey();\n\n    this.key = `${startVertexKey}_${endVertexKey}`;\n\n    return this.key;\n  }\n\n  /**\n   * @return {GraphEdge}\n   */\n  reverse() {\n    const tmp = this.startVertex;\n    this.startVertex = this.endVertex;\n    this.endVertex = tmp;\n\n    return this;\n  }\n\n  /**\n   * @return {string}\n   */\n  toString() {\n    return this.getKey().toString();\n  }\n}\n"
  },
  {
    "path": "src/data-structures/graph/GraphVertex.js",
    "content": "import LinkedList from '../linked-list/LinkedList';\n\nexport default class GraphVertex {\n  /**\n   * @param {*} value\n   */\n  constructor(value) {\n    if (value === undefined) {\n      throw new Error('Graph vertex must have a value');\n    }\n\n    /**\n     * @param {GraphEdge} edgeA\n     * @param {GraphEdge} edgeB\n     */\n    const edgeComparator = (edgeA, edgeB) => {\n      if (edgeA.getKey() === edgeB.getKey()) {\n        return 0;\n      }\n\n      return edgeA.getKey() < edgeB.getKey() ? -1 : 1;\n    };\n\n    // Normally you would store string value like vertex name.\n    // But generally it may be any object as well\n    this.value = value;\n    this.edges = new LinkedList(edgeComparator);\n  }\n\n  /**\n   * @param {GraphEdge} edge\n   * @returns {GraphVertex}\n   */\n  addEdge(edge) {\n    this.edges.append(edge);\n\n    return this;\n  }\n\n  /**\n   * @param {GraphEdge} edge\n   */\n  deleteEdge(edge) {\n    this.edges.delete(edge);\n  }\n\n  /**\n   * @returns {GraphVertex[]}\n   */\n  getNeighbors() {\n    const edges = this.edges.toArray();\n\n    /** @param {LinkedListNode} node */\n    const neighborsConverter = (node) => {\n      return node.value.startVertex === this ? node.value.endVertex : node.value.startVertex;\n    };\n\n    // Return either start or end vertex.\n    // For undirected graphs it is possible that current vertex will be the end one.\n    return edges.map(neighborsConverter);\n  }\n\n  /**\n   * @return {GraphEdge[]}\n   */\n  getEdges() {\n    return this.edges.toArray().map((linkedListNode) => linkedListNode.value);\n  }\n\n  /**\n   * @return {number}\n   */\n  getDegree() {\n    return this.edges.toArray().length;\n  }\n\n  /**\n   * @param {GraphEdge} requiredEdge\n   * @returns {boolean}\n   */\n  hasEdge(requiredEdge) {\n    const edgeNode = this.edges.find({\n      callback: (edge) => edge === requiredEdge,\n    });\n\n    return !!edgeNode;\n  }\n\n  /**\n   * @param {GraphVertex} vertex\n   * @returns {boolean}\n   */\n  hasNeighbor(vertex) {\n    const vertexNode = this.edges.find({\n      callback: (edge) => edge.startVertex === vertex || edge.endVertex === vertex,\n    });\n\n    return !!vertexNode;\n  }\n\n  /**\n   * @param {GraphVertex} vertex\n   * @returns {(GraphEdge|null)}\n   */\n  findEdge(vertex) {\n    const edgeFinder = (edge) => {\n      return edge.startVertex === vertex || edge.endVertex === vertex;\n    };\n\n    const edge = this.edges.find({ callback: edgeFinder });\n\n    return edge ? edge.value : null;\n  }\n\n  /**\n   * @returns {string}\n   */\n  getKey() {\n    return this.value;\n  }\n\n  /**\n   * @return {GraphVertex}\n   */\n  deleteAllEdges() {\n    this.getEdges().forEach((edge) => this.deleteEdge(edge));\n\n    return this;\n  }\n\n  /**\n   * @param {function} [callback]\n   * @returns {string}\n   */\n  toString(callback) {\n    return callback ? callback(this.value).toString() : this.value.toString();\n  }\n}\n"
  },
  {
    "path": "src/data-structures/graph/README.fr-FR.md",
    "content": "# Graph\n\nEn informatique, un **graphe** est une structure de\ndonnées abstraite qui implémente les concepts de\ngraphe orienté et de graphe non-orienté venant\ndes mathématiques, plus précisément du domaine de\nla théorie des graphes.\n\nLa structure de données abstraite de graphe consiste\nen un ensemble fini, éventuellement mutable de sommets\nou nœuds ou points, avec un ensemble de paires ordonnées\nou non de tels éléments. Ces paires sont des arêtes, arcs\nnon orientés, ou lignes pour un graphe non orienté, et\nflèches, arêtes orientées , arcs, ou lignes orientées\ndans le cas orienté. Les sommets peuvent faire partie\nde la structure, ou être des entités extérieures,\nreprésentées par des entiers ou des références.\n\n![Graph](./images/graph.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/Graphe_(type_abstrait))\n"
  },
  {
    "path": "src/data-structures/graph/README.md",
    "content": "# Graph\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md),\n[_Українська_](README.uk-UA.md)\n\n\nIn computer science, a **graph** is an abstract data type\nthat is meant to implement the undirected graph and\ndirected graph concepts from mathematics, specifically\nthe field of graph theory\n\nA graph data structure consists of a finite (and possibly\nmutable) set of vertices or nodes or points, together\nwith a set of unordered pairs of these vertices for an\nundirected graph or a set of ordered pairs for a\ndirected graph. These pairs are known as edges, arcs,\nor lines for an undirected graph and as arrows,\ndirected edges, directed arcs, or directed lines\nfor a directed graph. The vertices may be part of\nthe graph structure, or may be external entities\nrepresented by integer indices or references.\n\n![Graph](./images/graph.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))\n- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/graph/README.pt-BR.md",
    "content": "# Grafo (Graph)\n\nNa ciência da computação, um **grafo** é uma abstração de estrutura\nde dados que se destina a implementar os conceitos da matemática de\ngrafos direcionados e não direcionados, especificamente o campo da\nteoria dos grafos.\n\nUma estrutura de dados grafos consiste em um finito (e possivelmente\nmutável) conjunto de vértices, nós ou pontos, juntos com um\nconjunto de pares não ordenados desses vértices para um grafo não\ndirecionado ou para um conjunto de pares ordenados para um grafo\ndirecionado. Esses pares são conhecidos como arestas, arcos\nou linhas diretas para um grafo não direcionado e como setas,\narestas direcionadas, arcos direcionados ou linhas direcionadas\npara um grafo direcionado.\n\nOs vértices podem fazer parte a estrutura do grafo, ou podem\nser entidades externas representadas por índices inteiros ou referências.\n\n![Graph](./images/graph.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))\n- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/graph/README.ru-RU.md",
    "content": "# Граф\n\n**Граф** в информатике - абстрактный тип данных, который должен реализовывать концепции направленного и ненаправленного\nграфа в математике, особенно в области теории графов.\n\nСтруктура данных графа состоит из конечного (и возможно изменяющегося) набора вершин или узлов, или точек, совместно с\nнабором ненаправленных пар этих вершин для ненаправленного графа или с набором направленных пар для направленного графа.\nЭти пары известны как рёбра, арки или линии для ненаправленного графа и как стрелки, направленные рёбра, направленные\nарки или направленные линии для направленного графа. Эти вершины могут быть частью структуры графа, или внешними\nсущностями, представленными целочисленными индексами или ссылками.\n\nДля разных областей применения виды графов могут различаться направленностью, ограничениями на количество связей и\nдополнительными данными о вершинах или рёбрах. Многие структуры, представляющие практический интерес в математике и\nинформатике, могут быть представлены графами. Например, строение Википедии можно смоделировать при помощи\nориентированного графа, в котором вершины — это статьи, а дуги (ориентированные рёбра) — гиперссылки.\n\n![Граф](./images/graph.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Ссылки\n\n- [Граф в математике на 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))\n- [Графы на YouTube. Часть 1(~10 мин)](https://www.youtube.com/watch?v=GOUuhJPLG3s)\n- [Графы на YouTube. Часть 2(~10 мин)](https://www.youtube.com/watch?v=N-kCJJkTk7g)\n- [Графы на YouTube. Часть 3(~10 мин)](https://www.youtube.com/watch?v=2o3TINew0b8)\n"
  },
  {
    "path": "src/data-structures/graph/README.uk-UA.md",
    "content": "# Граф\n\n**Граф** в інформатиці - абстрактний тип даних, який має реалізовувати концепції спрямованого та неспрямованого\nграфа у математиці, особливо у галузі теорії графів.\n\nСтруктура даних графа складається з кінцевого (і можливо, що змінюється) набору вершин або вузлів, або точок, спільно з\nнабором ненаправлених пар цих вершин для ненаправленого графа або набором спрямованих пар для спрямованого графа.\nЦі пари відомі як ребра, арки або лінії для ненаправленого графа та як стрілки, спрямовані ребра, спрямовані\nарки чи спрямовані лінії для спрямованого графа. Ці вершини можуть бути частиною структури графа, або зовнішніми\nсутностями, представленими цілими індексами або посиланнями.\n\nДля різних областей застосування види графів можуть відрізнятися спрямованістю, обмеженнями на кількість зв'язків та\nдодатковими даними про вершини або ребра. Багато структур, що становлять практичний інтерес у математиці та\nінформатики можуть бути представлені графами. Наприклад, будову Вікіпедії можна змоделювати за допомогою\nорієнтованого графа, в якому вершини – це статті, а дуги (орієнтовані ребра) – гіперпосилання.\n\n![Граф](./images/graph.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Посилання\n\n- [Граф у математиці на 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))\n- [Структура даних Graph / Граф](https://www.youtube.com/watch?v=D0U8aFEhgKQ)\n"
  },
  {
    "path": "src/data-structures/graph/README.zh-CN.md",
    "content": "# 图\n\n在计算机科学中, **图(graph)** 是一种抽象数据类型,\n旨在实现数学中的无向图和有向图概念，特别是图论领域。\n\n一个图数据结构是一个(由有限个或者可变数量的)顶点/节点/点和边构成的有限集。\n\n如果顶点对之间是无序的,称为无序图,否则称为有序图;\n\n如果顶点对之间的边是没有方向的,称为无向图,否则称为有向图;\n\n如果顶点对之间的边是有权重的,该图可称为加权图。\n\n![Graph](./images/graph.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))\n- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/graph/__test__/Graph.test.js",
    "content": "import Graph from '../Graph';\nimport GraphVertex from '../GraphVertex';\nimport GraphEdge from '../GraphEdge';\n\ndescribe('Graph', () => {\n  it('should add vertices to graph', () => {\n    const graph = new Graph();\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n\n    graph\n      .addVertex(vertexA)\n      .addVertex(vertexB);\n\n    expect(graph.toString()).toBe('A,B');\n    expect(graph.getVertexByKey(vertexA.getKey())).toEqual(vertexA);\n    expect(graph.getVertexByKey(vertexB.getKey())).toEqual(vertexB);\n  });\n\n  it('should add edges to undirected graph', () => {\n    const graph = new Graph();\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n\n    graph.addEdge(edgeAB);\n\n    expect(graph.getAllVertices().length).toBe(2);\n    expect(graph.getAllVertices()[0]).toEqual(vertexA);\n    expect(graph.getAllVertices()[1]).toEqual(vertexB);\n\n    const graphVertexA = graph.getVertexByKey(vertexA.getKey());\n    const graphVertexB = graph.getVertexByKey(vertexB.getKey());\n\n    expect(graph.toString()).toBe('A,B');\n    expect(graphVertexA).toBeDefined();\n    expect(graphVertexB).toBeDefined();\n\n    expect(graph.getVertexByKey('not existing')).toBeUndefined();\n\n    expect(graphVertexA.getNeighbors().length).toBe(1);\n    expect(graphVertexA.getNeighbors()[0]).toEqual(vertexB);\n    expect(graphVertexA.getNeighbors()[0]).toEqual(graphVertexB);\n\n    expect(graphVertexB.getNeighbors().length).toBe(1);\n    expect(graphVertexB.getNeighbors()[0]).toEqual(vertexA);\n    expect(graphVertexB.getNeighbors()[0]).toEqual(graphVertexA);\n  });\n\n  it('should add edges to directed graph', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n\n    graph.addEdge(edgeAB);\n\n    const graphVertexA = graph.getVertexByKey(vertexA.getKey());\n    const graphVertexB = graph.getVertexByKey(vertexB.getKey());\n\n    expect(graph.toString()).toBe('A,B');\n    expect(graphVertexA).toBeDefined();\n    expect(graphVertexB).toBeDefined();\n\n    expect(graphVertexA.getNeighbors().length).toBe(1);\n    expect(graphVertexA.getNeighbors()[0]).toEqual(vertexB);\n    expect(graphVertexA.getNeighbors()[0]).toEqual(graphVertexB);\n\n    expect(graphVertexB.getNeighbors().length).toBe(0);\n  });\n\n  it('should find edge by vertices in undirected graph', () => {\n    const graph = new Graph();\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 10);\n\n    graph.addEdge(edgeAB);\n\n    const graphEdgeAB = graph.findEdge(vertexA, vertexB);\n    const graphEdgeBA = graph.findEdge(vertexB, vertexA);\n    const graphEdgeAC = graph.findEdge(vertexA, vertexC);\n    const graphEdgeCA = graph.findEdge(vertexC, vertexA);\n\n    expect(graphEdgeAC).toBeNull();\n    expect(graphEdgeCA).toBeNull();\n    expect(graphEdgeAB).toEqual(edgeAB);\n    expect(graphEdgeBA).toEqual(edgeAB);\n    expect(graphEdgeAB.weight).toBe(10);\n  });\n\n  it('should find edge by vertices in directed graph', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 10);\n\n    graph.addEdge(edgeAB);\n\n    const graphEdgeAB = graph.findEdge(vertexA, vertexB);\n    const graphEdgeBA = graph.findEdge(vertexB, vertexA);\n    const graphEdgeAC = graph.findEdge(vertexA, vertexC);\n    const graphEdgeCA = graph.findEdge(vertexC, vertexA);\n\n    expect(graphEdgeAC).toBeNull();\n    expect(graphEdgeCA).toBeNull();\n    expect(graphEdgeBA).toBeNull();\n    expect(graphEdgeAB).toEqual(edgeAB);\n    expect(graphEdgeAB.weight).toBe(10);\n  });\n\n  it('should return vertex neighbors', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC);\n\n    const neighbors = graph.getNeighbors(vertexA);\n\n    expect(neighbors.length).toBe(2);\n    expect(neighbors[0]).toEqual(vertexB);\n    expect(neighbors[1]).toEqual(vertexC);\n  });\n\n  it('should throw an error when trying to add edge twice', () => {\n    function addSameEdgeTwice() {\n      const graph = new Graph(true);\n\n      const vertexA = new GraphVertex('A');\n      const vertexB = new GraphVertex('B');\n\n      const edgeAB = new GraphEdge(vertexA, vertexB);\n\n      graph\n        .addEdge(edgeAB)\n        .addEdge(edgeAB);\n    }\n\n    expect(addSameEdgeTwice).toThrow();\n  });\n\n  it('should throw an error when trying to add vertex twice', () => {\n    function addSameEdgeTwice() {\n      const graph = new Graph(true);\n      const vertexA = new GraphVertex('A');\n\n      graph\n        .addVertex(vertexA)\n        .addVertex(vertexA);\n    }\n\n    expect(addSameEdgeTwice).toThrow();\n  });\n\n  it('should return the list of all added edges', () => {\n    const graph = new Graph(true);\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC);\n\n    const edges = graph.getAllEdges();\n\n    expect(edges.length).toBe(2);\n    expect(edges[0]).toEqual(edgeAB);\n    expect(edges[1]).toEqual(edgeBC);\n  });\n\n  it('should calculate total graph weight for default graph', () => {\n    const graph = new Graph();\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeAD = new GraphEdge(vertexA, vertexD);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeAD);\n\n    expect(graph.getWeight()).toBe(0);\n  });\n\n  it('should calculate total graph weight for weighted graph', () => {\n    const graph = new Graph();\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 1);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 2);\n    const edgeCD = new GraphEdge(vertexC, vertexD, 3);\n    const edgeAD = new GraphEdge(vertexA, vertexD, 4);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeAD);\n\n    expect(graph.getWeight()).toBe(10);\n  });\n\n  it('should be possible to delete edges from graph', () => {\n    const graph = new Graph();\n\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeAC);\n\n    expect(graph.getAllEdges().length).toBe(3);\n\n    graph.deleteEdge(edgeAB);\n\n    expect(graph.getAllEdges().length).toBe(2);\n    expect(graph.getAllEdges()[0].getKey()).toBe(edgeBC.getKey());\n    expect(graph.getAllEdges()[1].getKey()).toBe(edgeAC.getKey());\n  });\n\n  it('should should throw an error when trying to delete not existing edge', () => {\n    function deleteNotExistingEdge() {\n      const graph = new Graph();\n\n      const vertexA = new GraphVertex('A');\n      const vertexB = new GraphVertex('B');\n      const vertexC = new GraphVertex('C');\n\n      const edgeAB = new GraphEdge(vertexA, vertexB);\n      const edgeBC = new GraphEdge(vertexB, vertexC);\n\n      graph.addEdge(edgeAB);\n      graph.deleteEdge(edgeBC);\n    }\n\n    expect(deleteNotExistingEdge).toThrow();\n  });\n\n  it('should be possible to reverse graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n\n    const graph = new Graph(true);\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeAC)\n      .addEdge(edgeCD);\n\n    expect(graph.toString()).toBe('A,B,C,D');\n    expect(graph.getAllEdges().length).toBe(3);\n    expect(graph.getNeighbors(vertexA).length).toBe(2);\n    expect(graph.getNeighbors(vertexA)[0].getKey()).toBe(vertexB.getKey());\n    expect(graph.getNeighbors(vertexA)[1].getKey()).toBe(vertexC.getKey());\n    expect(graph.getNeighbors(vertexB).length).toBe(0);\n    expect(graph.getNeighbors(vertexC).length).toBe(1);\n    expect(graph.getNeighbors(vertexC)[0].getKey()).toBe(vertexD.getKey());\n    expect(graph.getNeighbors(vertexD).length).toBe(0);\n\n    graph.reverse();\n\n    expect(graph.toString()).toBe('A,B,C,D');\n    expect(graph.getAllEdges().length).toBe(3);\n    expect(graph.getNeighbors(vertexA).length).toBe(0);\n    expect(graph.getNeighbors(vertexB).length).toBe(1);\n    expect(graph.getNeighbors(vertexB)[0].getKey()).toBe(vertexA.getKey());\n    expect(graph.getNeighbors(vertexC).length).toBe(1);\n    expect(graph.getNeighbors(vertexC)[0].getKey()).toBe(vertexA.getKey());\n    expect(graph.getNeighbors(vertexD).length).toBe(1);\n    expect(graph.getNeighbors(vertexD)[0].getKey()).toBe(vertexC.getKey());\n  });\n\n  it('should return vertices indices', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeBD = new GraphEdge(vertexB, vertexD);\n\n    const graph = new Graph();\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeBD);\n\n    const verticesIndices = graph.getVerticesIndices();\n    expect(verticesIndices).toEqual({\n      A: 0,\n      B: 1,\n      C: 2,\n      D: 3,\n    });\n  });\n\n  it('should generate adjacency matrix for undirected graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeBC = new GraphEdge(vertexB, vertexC);\n    const edgeCD = new GraphEdge(vertexC, vertexD);\n    const edgeBD = new GraphEdge(vertexB, vertexD);\n\n    const graph = new Graph();\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeBD);\n\n    const adjacencyMatrix = graph.getAdjacencyMatrix();\n    expect(adjacencyMatrix).toEqual([\n      [Infinity, 0, Infinity, Infinity],\n      [0, Infinity, 0, 0],\n      [Infinity, 0, Infinity, 0],\n      [Infinity, 0, 0, Infinity],\n    ]);\n  });\n\n  it('should generate adjacency matrix for directed graph', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n    const vertexD = new GraphVertex('D');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB, 2);\n    const edgeBC = new GraphEdge(vertexB, vertexC, 1);\n    const edgeCD = new GraphEdge(vertexC, vertexD, 5);\n    const edgeBD = new GraphEdge(vertexB, vertexD, 7);\n\n    const graph = new Graph(true);\n    graph\n      .addEdge(edgeAB)\n      .addEdge(edgeBC)\n      .addEdge(edgeCD)\n      .addEdge(edgeBD);\n\n    const adjacencyMatrix = graph.getAdjacencyMatrix();\n    expect(adjacencyMatrix).toEqual([\n      [Infinity, 2, Infinity, Infinity],\n      [Infinity, Infinity, 1, 7],\n      [Infinity, Infinity, Infinity, 5],\n      [Infinity, Infinity, Infinity, Infinity],\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/graph/__test__/GraphEdge.test.js",
    "content": "import GraphEdge from '../GraphEdge';\nimport GraphVertex from '../GraphVertex';\n\ndescribe('GraphEdge', () => {\n  it('should create graph edge with default weight', () => {\n    const startVertex = new GraphVertex('A');\n    const endVertex = new GraphVertex('B');\n    const edge = new GraphEdge(startVertex, endVertex);\n\n    expect(edge.startVertex).toEqual(startVertex);\n    expect(edge.endVertex).toEqual(endVertex);\n    expect(edge.weight).toEqual(0);\n  });\n\n  it('should create graph edge with predefined weight', () => {\n    const startVertex = new GraphVertex('A');\n    const endVertex = new GraphVertex('B');\n    const edge = new GraphEdge(startVertex, endVertex, 10);\n\n    expect(edge.startVertex).toEqual(startVertex);\n    expect(edge.endVertex).toEqual(endVertex);\n    expect(edge.weight).toEqual(10);\n  });\n\n  it('should be possible to do edge reverse', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const edge = new GraphEdge(vertexA, vertexB, 10);\n\n    expect(edge.startVertex).toEqual(vertexA);\n    expect(edge.endVertex).toEqual(vertexB);\n    expect(edge.weight).toEqual(10);\n\n    edge.reverse();\n\n    expect(edge.startVertex).toEqual(vertexB);\n    expect(edge.endVertex).toEqual(vertexA);\n    expect(edge.weight).toEqual(10);\n  });\n\n  it('should return edges names as key', () => {\n    const edge = new GraphEdge(new GraphVertex('A'), new GraphVertex('B'), 0);\n\n    expect(edge.getKey()).toBe('A_B');\n    expect(edge.toString()).toBe('A_B');\n  });\n\n  it('should return custom key if defined', () => {\n    const edge = new GraphEdge(new GraphVertex('A'), new GraphVertex('B'), 0, 'custom_key');\n\n    expect(edge.getKey()).toEqual('custom_key');\n    expect(edge.toString()).toEqual('custom_key');\n  });\n\n  it('should execute toString on key  when calling toString on edge', () => {\n    const customKey = {\n      toString() { return 'custom_key'; },\n    };\n\n    const edge = new GraphEdge(new GraphVertex('A'), new GraphVertex('B'), 0, customKey);\n\n    expect(edge.getKey()).toEqual(customKey);\n    expect(edge.toString()).toEqual('custom_key');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/graph/__test__/GraphVertex.test.js",
    "content": "import GraphVertex from '../GraphVertex';\nimport GraphEdge from '../GraphEdge';\n\ndescribe('GraphVertex', () => {\n  it('should throw an error when trying to create vertex without value', () => {\n    let vertex = null;\n\n    function createEmptyVertex() {\n      vertex = new GraphVertex();\n    }\n\n    expect(vertex).toBeNull();\n    expect(createEmptyVertex).toThrow();\n  });\n\n  it('should create graph vertex', () => {\n    const vertex = new GraphVertex('A');\n\n    expect(vertex).toBeDefined();\n    expect(vertex.value).toBe('A');\n    expect(vertex.toString()).toBe('A');\n    expect(vertex.getKey()).toBe('A');\n    expect(vertex.edges.toString()).toBe('');\n    expect(vertex.getEdges()).toEqual([]);\n  });\n\n  it('should add edges to vertex and check if it exists', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    vertexA.addEdge(edgeAB);\n\n    expect(vertexA.hasEdge(edgeAB)).toBe(true);\n    expect(vertexB.hasEdge(edgeAB)).toBe(false);\n    expect(vertexA.getEdges().length).toBe(1);\n    expect(vertexA.getEdges()[0].toString()).toBe('A_B');\n  });\n\n  it('should delete edges from vertex', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    vertexA\n      .addEdge(edgeAB)\n      .addEdge(edgeAC);\n\n    expect(vertexA.hasEdge(edgeAB)).toBe(true);\n    expect(vertexB.hasEdge(edgeAB)).toBe(false);\n\n    expect(vertexA.hasEdge(edgeAC)).toBe(true);\n    expect(vertexC.hasEdge(edgeAC)).toBe(false);\n\n    expect(vertexA.getEdges().length).toBe(2);\n\n    expect(vertexA.getEdges()[0].toString()).toBe('A_B');\n    expect(vertexA.getEdges()[1].toString()).toBe('A_C');\n\n    vertexA.deleteEdge(edgeAB);\n    expect(vertexA.hasEdge(edgeAB)).toBe(false);\n    expect(vertexA.hasEdge(edgeAC)).toBe(true);\n    expect(vertexA.getEdges()[0].toString()).toBe('A_C');\n\n    vertexA.deleteEdge(edgeAC);\n    expect(vertexA.hasEdge(edgeAB)).toBe(false);\n    expect(vertexA.hasEdge(edgeAC)).toBe(false);\n    expect(vertexA.getEdges().length).toBe(0);\n  });\n\n  it('should delete all edges from vertex', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    vertexA\n      .addEdge(edgeAB)\n      .addEdge(edgeAC);\n\n    expect(vertexA.hasEdge(edgeAB)).toBe(true);\n    expect(vertexB.hasEdge(edgeAB)).toBe(false);\n\n    expect(vertexA.hasEdge(edgeAC)).toBe(true);\n    expect(vertexC.hasEdge(edgeAC)).toBe(false);\n\n    expect(vertexA.getEdges().length).toBe(2);\n\n    vertexA.deleteAllEdges();\n\n    expect(vertexA.hasEdge(edgeAB)).toBe(false);\n    expect(vertexB.hasEdge(edgeAB)).toBe(false);\n\n    expect(vertexA.hasEdge(edgeAC)).toBe(false);\n    expect(vertexC.hasEdge(edgeAC)).toBe(false);\n\n    expect(vertexA.getEdges().length).toBe(0);\n  });\n\n  it('should return vertex neighbors in case if current node is start one', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    const edgeAC = new GraphEdge(vertexA, vertexC);\n    vertexA\n      .addEdge(edgeAB)\n      .addEdge(edgeAC);\n\n    expect(vertexB.getNeighbors()).toEqual([]);\n\n    const neighbors = vertexA.getNeighbors();\n\n    expect(neighbors.length).toBe(2);\n    expect(neighbors[0]).toEqual(vertexB);\n    expect(neighbors[1]).toEqual(vertexC);\n  });\n\n  it('should return vertex neighbors in case if current node is end one', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeBA = new GraphEdge(vertexB, vertexA);\n    const edgeCA = new GraphEdge(vertexC, vertexA);\n    vertexA\n      .addEdge(edgeBA)\n      .addEdge(edgeCA);\n\n    expect(vertexB.getNeighbors()).toEqual([]);\n\n    const neighbors = vertexA.getNeighbors();\n\n    expect(neighbors.length).toBe(2);\n    expect(neighbors[0]).toEqual(vertexB);\n    expect(neighbors[1]).toEqual(vertexC);\n  });\n\n  it('should check if vertex has specific neighbor', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    vertexA.addEdge(edgeAB);\n\n    expect(vertexA.hasNeighbor(vertexB)).toBe(true);\n    expect(vertexA.hasNeighbor(vertexC)).toBe(false);\n  });\n\n  it('should edge by vertex', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n    const vertexC = new GraphVertex('C');\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    vertexA.addEdge(edgeAB);\n\n    expect(vertexA.findEdge(vertexB)).toEqual(edgeAB);\n    expect(vertexA.findEdge(vertexC)).toBeNull();\n  });\n\n  it('should calculate vertex degree', () => {\n    const vertexA = new GraphVertex('A');\n    const vertexB = new GraphVertex('B');\n\n    expect(vertexA.getDegree()).toBe(0);\n\n    const edgeAB = new GraphEdge(vertexA, vertexB);\n    vertexA.addEdge(edgeAB);\n\n    expect(vertexA.getDegree()).toBe(1);\n\n    const edgeBA = new GraphEdge(vertexB, vertexA);\n    vertexA.addEdge(edgeBA);\n\n    expect(vertexA.getDegree()).toBe(2);\n\n    vertexA.addEdge(edgeAB);\n    expect(vertexA.getDegree()).toBe(3);\n\n    expect(vertexA.getEdges().length).toEqual(3);\n  });\n\n  it('should execute callback when passed to toString', () => {\n    const vertex = new GraphVertex('A');\n\n    expect(vertex.toString(() => 'B')).toEqual('B');\n  });\n\n  it('should execute toString on value when calling toString on vertex', () => {\n    const value = {\n      toString() { return 'A'; },\n    };\n\n    const vertex = new GraphVertex(value);\n\n    expect(vertex.toString()).toEqual('A');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/hash-table/HashTable.js",
    "content": "import LinkedList from '../linked-list/LinkedList';\n\n// Hash table size directly affects on the number of collisions.\n// The bigger the hash table size the less collisions you'll get.\n// For demonstrating purposes hash table size is small to show how collisions\n// are being handled.\nconst defaultHashTableSize = 32;\n\nexport default class HashTable {\n  /**\n   * @param {number} hashTableSize\n   */\n  constructor(hashTableSize = defaultHashTableSize) {\n    // Create hash table of certain size and fill each bucket with empty linked list.\n    this.buckets = Array(hashTableSize).fill(null).map(() => new LinkedList());\n\n    // Just to keep track of all actual keys in a fast way.\n    this.keys = {};\n  }\n\n  /**\n   * Converts key string to hash number.\n   *\n   * @param {string} key\n   * @return {number}\n   */\n  hash(key) {\n    // For simplicity reasons we will just use character codes sum of all characters of the key\n    // to calculate the hash.\n    //\n    // But you may also use more sophisticated approaches like polynomial string hash to reduce the\n    // number of collisions:\n    //\n    // hash = charCodeAt(0) * PRIME^(n-1) + charCodeAt(1) * PRIME^(n-2) + ... + charCodeAt(n-1)\n    //\n    // where charCodeAt(i) is the i-th character code of the key, n is the length of the key and\n    // PRIME is just any prime number like 31.\n    const hash = Array.from(key).reduce(\n      (hashAccumulator, keySymbol) => (hashAccumulator + keySymbol.charCodeAt(0)),\n      0,\n    );\n\n    // Reduce hash number so it would fit hash table size.\n    return hash % this.buckets.length;\n  }\n\n  /**\n   * @param {string} key\n   * @param {*} value\n   */\n  set(key, value) {\n    const keyHash = this.hash(key);\n    this.keys[key] = keyHash;\n    const bucketLinkedList = this.buckets[keyHash];\n    const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });\n\n    if (!node) {\n      // Insert new node.\n      bucketLinkedList.append({ key, value });\n    } else {\n      // Update value of existing node.\n      node.value.value = value;\n    }\n  }\n\n  /**\n   * @param {string} key\n   * @return {*}\n   */\n  delete(key) {\n    const keyHash = this.hash(key);\n    delete this.keys[key];\n    const bucketLinkedList = this.buckets[keyHash];\n    const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });\n\n    if (node) {\n      return bucketLinkedList.delete(node.value);\n    }\n\n    return null;\n  }\n\n  /**\n   * @param {string} key\n   * @return {*}\n   */\n  get(key) {\n    const bucketLinkedList = this.buckets[this.hash(key)];\n    const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });\n\n    return node ? node.value.value : undefined;\n  }\n\n  /**\n   * @param {string} key\n   * @return {boolean}\n   */\n  has(key) {\n    return Object.hasOwnProperty.call(this.keys, key);\n  }\n\n  /**\n   * @return {string[]}\n   */\n  getKeys() {\n    return Object.keys(this.keys);\n  }\n\n  /**\n   * Gets the list of all the stored values in the hash table.\n   *\n   * @return {*[]}\n   */\n  getValues() {\n    return this.buckets.reduce((values, bucket) => {\n      const bucketValues = bucket.toArray()\n        .map((linkedListNode) => linkedListNode.value.value);\n      return values.concat(bucketValues);\n    }, []);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/hash-table/README.fr-FR.md",
    "content": "# Table de hachage\n\nEn informatique, une **table de hachage** (carte de\nhachage) est une structure de données qui implémente\nun type de données abstrait *tableau nassociatif*,\nune structure qui permet de *mapper des clés sur des\nvaleurs*. Une table de hachage utilise une *fonction\nde hachage* pour calculer un index dans un tableau\nd'alvéoles (en anglais, buckets ou slots), à partir\nduquel la valeur souhaitée peut être trouvée.\n\nIdéalement, la fonction de hachage affectera chaque clé\nà une alvéole unique, mais la plupart des tables de\nhachage conçues emploient une fonction de hachage\nimparfaite, ce qui peut provoquer des collisions de\nhachage où la fonction de hachage génère le même index\npour plusieurs clés. De telles collisions doivent être\naccommodées d'une manière ou d'une autre.\n\n![Hash Table](./images/hash-table.jpeg)\n\nCollision de hachage résolue par chaînage séparé.\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Références\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/Table_de_hachage)\n- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/hash-table/README.ja-JP.md",
    "content": "# ハッシュテーブル\n\nコンピュータサイエンスにおいて、**ハッシュテーブル**（ハッシュマップ)は*キーを値にマッピング*できる*連想配列*の機能を持ったデータ構造です。ハッシュテーブルは*ハッシュ関数*を使ってバケットやスロットの配列へのインデックスを計算し、そこから目的の値を見つけることができます。\n\n理想的には、ハッシュ関数は各キーを一意のバケットに割り当てますが、ほとんどのハッシュテーブルは不完全なハッシュ関数を採用しているため、複数のキーに対して同じインデックスを生成した時にハッシュの衝突が起こります。このような衝突は何らかの方法で対処する必要があります。\n\n![Hash Table](./images/hash-table.jpeg)\n\nチェイン法によるハッシュの衝突の解決例\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)\n- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/hash-table/README.ko-KR.md",
    "content": "# Hash Table\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md)\n\n컴퓨팅에서, **해시 테이블**(해시 맵)은 키를 값에 매핑할 수 있는 구조인 *연관 배열*을 구현하는 자료 구조입니다. 해시 테이블은 *해시 함수*를 사용해 원하는 값을 담을 수 있는 버킷 또는 슬롯 배열의 인덱스를 계산합니다.\n\n이상적으로, 해시 함수는 각 키들을 고유 버킷에 할당하지만 대부분의 해시 테이블은 불완전한 해시 함수를 사용하기 때문에 해시 함수를 통해 두 개 이상의 키에 대해 동일한 인덱스를 생성하는 해시 충돌이 발생할 수 있습니다. 이러한 해시 충돌은 어떠한 방법으로든 해결되어야 합니다.\n\n![Hash Table](./images/hash-table.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n다음은 분리 연결법을 통해 해시 충돌을 해결한 예시입니다.\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 참고\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)\n- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/hash-table/README.md",
    "content": "# Hash Table\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Українська_](README.uk-UA.md)\n\nIn computing, a **hash table** (hash map) is a data\nstructure which implements an _associative array_\nabstract data type, a structure that can _map keys\nto values_. A hash table uses a _hash function_ to\ncompute an index into an array of buckets or slots,\nfrom which the desired value can be found\n\nIdeally, the hash function will assign each key to a\nunique bucket, but most hash table designs employ an\nimperfect hash function, which might cause hash\ncollisions where the hash function generates the same\nindex for more than one key. Such collisions must be\naccommodated in some way.\n\n![Hash Table](./images/hash-table.jpeg)\n\nHash collision resolved by separate chaining.\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n_Made with [okso.app](https://okso.app)_\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)\n- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/hash-table/README.pt-BR.md",
    "content": "# Tabela de Hash (Hash Table)\n\nNa ciência da computação, uma **tabela de hash** (hash table) é uma\nestrutura de dados pela qual implementa um tipo de dado abstrado de\n*array associativo*, uma estrutura que pode *mapear chaves para valores*.\nUma tabela de hash utiliza uma *função de hash* para calcular um índice\nem um _array_ de buckets ou slots, a partir do qual o valor desejado\npode ser encontrado.\n\nIdealmente, a função de hash irá atribuir a cada chave a um bucket único,\nmas a maioria dos designs de tabela de hash emprega uma função de hash\nimperfeita, pela qual poderá causar colisões de hashes onde a função de hash\ngera o mesmo índice para mais de uma chave. Tais colisões devem ser\nacomodados de alguma forma.\n\n![Hash Table](./images/hash-table.jpeg)\n\nColisão de hash resolvida por encadeamento separado.\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)\n- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/hash-table/README.ru-RU.md",
    "content": "# Хэш таблица\n\n**Хеш-таблица** - структура данных, реализующая абстрактный тип данных *ассоциативный массив*, т.е. структура, которая\n*связывает ключи со значениями*. Хеш-таблица использует *хеш-функцию* для вычисления индекса в массиве, в котором может\nбыть найдено желаемое значение. Ниже представлена хеш-таблица, в которой ключом выступает имя человека, а значениями\nявляются телефонные номера. Хеш-функция преобразует ключ-имя в индекс массива с телефонными номерами.\n\n![Hash Table](./images/hash-table.jpeg)\n\nВ идеале хеш-функция будет присваивать элементу массива уникальный ключ. Однако большинство реальных хеш-таблиц\nиспользуют несовершенные хеш-функции. Это может привести к ситуациям, когда хеш-функция генерирует одинаковый индекс для\nнескольких ключей. Данные ситуации называются коллизиями и должны быть как-то разрешены.\n\nСуществует два варианта решения коллизий - хеш-таблица с цепочками и с открытой адресацией.\n\nМетод цепочек подразумевает хранение значений, соответствующих одному и тому же индексу в виде связного списка(цепочки).\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nМетод открытой адресации помещает значение, для которого получен дублирующий индекс, в первую свободную ячейку.\n\n![Хеш открытая адресация](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)\n\n## Ссылки\n\n- [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)\n- [YouTube](https://www.youtube.com/watch?v=rVr1y32fDI0)\n"
  },
  {
    "path": "src/data-structures/hash-table/README.uk-UA.md",
    "content": "# Геш таблиця\n\n**Геш таблиця** - структура даних, що реалізує абстрактний тип даних асоціативний масив, тобто. структура, яка\n_зв'язує ключі зі значеннями_. Геш-таблиця використовує _геш-функцію_ для обчислення індексу в масиві, в якому може\nбути знайдено бажане значення. Нижче представлена геш-таблиця, у якій ключем виступає ім'я людини, а значеннями\nтелефонні номери. Геш-функція перетворює ключ-ім'я на індекс масиву з телефонними номерами.\n\n![Hash Table](./images/hash-table.jpeg)\n\nВ ідеалі геш-функція присвоюватиме елементу масиву унікальний ключ. Проте більшість реальних геш-таблиць\nвикористовують недосконалі геш-функції. Це може призвести до ситуацій, коли геш-функція генерує однаковий індекс для\nкількох ключів. Ці ситуації називаються колізіями і мають бути якось вирішені.\n\nІснує два варіанти вирішення колізій - геш-таблиця з ланцюжками та з відкритою адресацією.\n\nМетод ланцюжків передбачає зберігання значень, відповідних одному й тому індексу як зв'язкового списку(ланцюжка).\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n_Made with [okso.app](https://okso.app)_\n\nМетод відкритої адресації поміщає значення, для якого отримано дублюючий індекс, в першу вільну комірку.\n\n![Геш відкрита адресація](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)\n\n## Посилання\n\n- [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)\n- [YouTube](https://www.youtube.com/watch?v=WTYaboK-NMk)\n"
  },
  {
    "path": "src/data-structures/hash-table/README.zh-CN.md",
    "content": "# 哈希表\n\n在计算中, 一个  **哈希表(hash table 或hash map)**  是一种实现 *关联数组(associative array)*\n的抽象数据类型, 该结构可以将 *键映射到值*。\n\n哈希表使用 *哈希函数/散列函数* 来计算一个值在数组或桶(buckets)中或槽(slots)中对应的索引,可使用该索引找到所需的值。\n\n理想情况下,散列函数将为每个键分配给一个唯一的桶(bucket),但是大多数哈希表设计采用不完美的散列函数,这可能会导致\"哈希冲突(hash collisions)\",也就是散列函数为多个键(key)生成了相同的索引,这种碰撞必须\n以某种方式进行处理。\n\n\n![Hash Table](./images/hash-table.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n通过单独的链接解决哈希冲突\n\n![Hash Collision](./images/collision-resolution.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)\n- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/hash-table/__test__/HashTable.test.js",
    "content": "import HashTable from '../HashTable';\n\ndescribe('HashTable', () => {\n  it('should create hash table of certain size', () => {\n    const defaultHashTable = new HashTable();\n    expect(defaultHashTable.buckets.length).toBe(32);\n\n    const biggerHashTable = new HashTable(64);\n    expect(biggerHashTable.buckets.length).toBe(64);\n  });\n\n  it('should generate proper hash for specified keys', () => {\n    const hashTable = new HashTable();\n\n    expect(hashTable.hash('a')).toBe(1);\n    expect(hashTable.hash('b')).toBe(2);\n    expect(hashTable.hash('abc')).toBe(6);\n  });\n\n  it('should set, read and delete data with collisions', () => {\n    const hashTable = new HashTable(3);\n\n    expect(hashTable.hash('a')).toBe(1);\n    expect(hashTable.hash('b')).toBe(2);\n    expect(hashTable.hash('c')).toBe(0);\n    expect(hashTable.hash('d')).toBe(1);\n\n    hashTable.set('a', 'sky-old');\n    hashTable.set('a', 'sky');\n    hashTable.set('b', 'sea');\n    hashTable.set('c', 'earth');\n    hashTable.set('d', 'ocean');\n\n    expect(hashTable.has('x')).toBe(false);\n    expect(hashTable.has('b')).toBe(true);\n    expect(hashTable.has('c')).toBe(true);\n\n    const stringifier = (value) => `${value.key}:${value.value}`;\n\n    expect(hashTable.buckets[0].toString(stringifier)).toBe('c:earth');\n    expect(hashTable.buckets[1].toString(stringifier)).toBe('a:sky,d:ocean');\n    expect(hashTable.buckets[2].toString(stringifier)).toBe('b:sea');\n\n    expect(hashTable.get('a')).toBe('sky');\n    expect(hashTable.get('d')).toBe('ocean');\n    expect(hashTable.get('x')).not.toBeDefined();\n\n    hashTable.delete('a');\n\n    expect(hashTable.delete('not-existing')).toBeNull();\n\n    expect(hashTable.get('a')).not.toBeDefined();\n    expect(hashTable.get('d')).toBe('ocean');\n\n    hashTable.set('d', 'ocean-new');\n    expect(hashTable.get('d')).toBe('ocean-new');\n  });\n\n  it('should be possible to add objects to hash table', () => {\n    const hashTable = new HashTable();\n\n    hashTable.set('objectKey', { prop1: 'a', prop2: 'b' });\n\n    const object = hashTable.get('objectKey');\n    expect(object).toBeDefined();\n    expect(object.prop1).toBe('a');\n    expect(object.prop2).toBe('b');\n  });\n\n  it('should track actual keys', () => {\n    const hashTable = new HashTable(3);\n\n    hashTable.set('a', 'sky-old');\n    hashTable.set('a', 'sky');\n    hashTable.set('b', 'sea');\n    hashTable.set('c', 'earth');\n    hashTable.set('d', 'ocean');\n\n    expect(hashTable.getKeys()).toEqual(['a', 'b', 'c', 'd']);\n    expect(hashTable.has('a')).toBe(true);\n    expect(hashTable.has('x')).toBe(false);\n\n    hashTable.delete('a');\n\n    expect(hashTable.has('a')).toBe(false);\n    expect(hashTable.has('b')).toBe(true);\n    expect(hashTable.has('x')).toBe(false);\n  });\n\n  it('should get all the values', () => {\n    const hashTable = new HashTable(3);\n\n    hashTable.set('a', 'alpha');\n    hashTable.set('b', 'beta');\n    hashTable.set('c', 'gamma');\n\n    expect(hashTable.getValues()).toEqual(['gamma', 'alpha', 'beta']);\n  });\n\n  it('should get all the values from empty hash table', () => {\n    const hashTable = new HashTable();\n    expect(hashTable.getValues()).toEqual([]);\n  });\n\n  it('should get all the values in case of hash collision', () => {\n    const hashTable = new HashTable(3);\n\n    // Keys `ab` and `ba` in current implementation should result in one hash (one bucket).\n    // We need to make sure that several items from one bucket will be serialized.\n    hashTable.set('ab', 'one');\n    hashTable.set('ba', 'two');\n\n    hashTable.set('ac', 'three');\n\n    expect(hashTable.getValues()).toEqual(['one', 'two', 'three']);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/heap/Heap.js",
    "content": "import Comparator from '../../utils/comparator/Comparator';\n\n/**\n * Parent class for Min and Max Heaps.\n */\nexport default class Heap {\n  /**\n   * @constructs Heap\n   * @param {Function} [comparatorFunction]\n   */\n  constructor(comparatorFunction) {\n    if (new.target === Heap) {\n      throw new TypeError('Cannot construct Heap instance directly');\n    }\n\n    // Array representation of the heap.\n    this.heapContainer = [];\n    this.compare = new Comparator(comparatorFunction);\n  }\n\n  /**\n   * @param {number} parentIndex\n   * @return {number}\n   */\n  getLeftChildIndex(parentIndex) {\n    return (2 * parentIndex) + 1;\n  }\n\n  /**\n   * @param {number} parentIndex\n   * @return {number}\n   */\n  getRightChildIndex(parentIndex) {\n    return (2 * parentIndex) + 2;\n  }\n\n  /**\n   * @param {number} childIndex\n   * @return {number}\n   */\n  getParentIndex(childIndex) {\n    return Math.floor((childIndex - 1) / 2);\n  }\n\n  /**\n   * @param {number} childIndex\n   * @return {boolean}\n   */\n  hasParent(childIndex) {\n    return this.getParentIndex(childIndex) >= 0;\n  }\n\n  /**\n   * @param {number} parentIndex\n   * @return {boolean}\n   */\n  hasLeftChild(parentIndex) {\n    return this.getLeftChildIndex(parentIndex) < this.heapContainer.length;\n  }\n\n  /**\n   * @param {number} parentIndex\n   * @return {boolean}\n   */\n  hasRightChild(parentIndex) {\n    return this.getRightChildIndex(parentIndex) < this.heapContainer.length;\n  }\n\n  /**\n   * @param {number} parentIndex\n   * @return {*}\n   */\n  leftChild(parentIndex) {\n    return this.heapContainer[this.getLeftChildIndex(parentIndex)];\n  }\n\n  /**\n   * @param {number} parentIndex\n   * @return {*}\n   */\n  rightChild(parentIndex) {\n    return this.heapContainer[this.getRightChildIndex(parentIndex)];\n  }\n\n  /**\n   * @param {number} childIndex\n   * @return {*}\n   */\n  parent(childIndex) {\n    return this.heapContainer[this.getParentIndex(childIndex)];\n  }\n\n  /**\n   * @param {number} indexOne\n   * @param {number} indexTwo\n   */\n  swap(indexOne, indexTwo) {\n    const tmp = this.heapContainer[indexTwo];\n    this.heapContainer[indexTwo] = this.heapContainer[indexOne];\n    this.heapContainer[indexOne] = tmp;\n  }\n\n  /**\n   * @return {*}\n   */\n  peek() {\n    if (this.heapContainer.length === 0) {\n      return null;\n    }\n\n    return this.heapContainer[0];\n  }\n\n  /**\n   * @return {*}\n   */\n  poll() {\n    if (this.heapContainer.length === 0) {\n      return null;\n    }\n\n    if (this.heapContainer.length === 1) {\n      return this.heapContainer.pop();\n    }\n\n    const item = this.heapContainer[0];\n\n    // Move the last element from the end to the head.\n    this.heapContainer[0] = this.heapContainer.pop();\n    this.heapifyDown();\n\n    return item;\n  }\n\n  /**\n   * @param {*} item\n   * @return {Heap}\n   */\n  add(item) {\n    this.heapContainer.push(item);\n    this.heapifyUp();\n    return this;\n  }\n\n  /**\n   * @param {*} item\n   * @param {Comparator} [comparator]\n   * @return {Heap}\n   */\n  remove(item, comparator = this.compare) {\n    // Find number of items to remove.\n    const numberOfItemsToRemove = this.find(item, comparator).length;\n\n    for (let iteration = 0; iteration < numberOfItemsToRemove; iteration += 1) {\n      // We need to find item index to remove each time after removal since\n      // indices are being changed after each heapify process.\n      const indexToRemove = this.find(item, comparator).pop();\n\n      // If we need to remove last child in the heap then just remove it.\n      // There is no need to heapify the heap afterwards.\n      if (indexToRemove === (this.heapContainer.length - 1)) {\n        this.heapContainer.pop();\n      } else {\n        // Move last element in heap to the vacant (removed) position.\n        this.heapContainer[indexToRemove] = this.heapContainer.pop();\n\n        // Get parent.\n        const parentItem = this.parent(indexToRemove);\n\n        // If there is no parent or parent is in correct order with the node\n        // we're going to delete then heapify down. Otherwise heapify up.\n        if (\n          this.hasLeftChild(indexToRemove)\n          && (\n            !parentItem\n            || this.pairIsInCorrectOrder(parentItem, this.heapContainer[indexToRemove])\n          )\n        ) {\n          this.heapifyDown(indexToRemove);\n        } else {\n          this.heapifyUp(indexToRemove);\n        }\n      }\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {*} item\n   * @param {Comparator} [comparator]\n   * @return {Number[]}\n   */\n  find(item, comparator = this.compare) {\n    const foundItemIndices = [];\n\n    for (let itemIndex = 0; itemIndex < this.heapContainer.length; itemIndex += 1) {\n      if (comparator.equal(item, this.heapContainer[itemIndex])) {\n        foundItemIndices.push(itemIndex);\n      }\n    }\n\n    return foundItemIndices;\n  }\n\n  /**\n   * @return {boolean}\n   */\n  isEmpty() {\n    return !this.heapContainer.length;\n  }\n\n  /**\n   * @return {string}\n   */\n  toString() {\n    return this.heapContainer.toString();\n  }\n\n  /**\n   * @param {number} [customStartIndex]\n   */\n  heapifyUp(customStartIndex) {\n    // Take the last element (last in array or the bottom left in a tree)\n    // in the heap container and lift it up until it is in the correct\n    // order with respect to its parent element.\n    let currentIndex = customStartIndex || this.heapContainer.length - 1;\n\n    while (\n      this.hasParent(currentIndex)\n      && !this.pairIsInCorrectOrder(this.parent(currentIndex), this.heapContainer[currentIndex])\n    ) {\n      this.swap(currentIndex, this.getParentIndex(currentIndex));\n      currentIndex = this.getParentIndex(currentIndex);\n    }\n  }\n\n  /**\n   * @param {number} [customStartIndex]\n   */\n  heapifyDown(customStartIndex = 0) {\n    // Compare the parent element to its children and swap parent with the appropriate\n    // child (smallest child for MinHeap, largest child for MaxHeap).\n    // Do the same for next children after swap.\n    let currentIndex = customStartIndex;\n    let nextIndex = null;\n\n    while (this.hasLeftChild(currentIndex)) {\n      if (\n        this.hasRightChild(currentIndex)\n        && this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex))\n      ) {\n        nextIndex = this.getRightChildIndex(currentIndex);\n      } else {\n        nextIndex = this.getLeftChildIndex(currentIndex);\n      }\n\n      if (this.pairIsInCorrectOrder(\n        this.heapContainer[currentIndex],\n        this.heapContainer[nextIndex],\n      )) {\n        break;\n      }\n\n      this.swap(currentIndex, nextIndex);\n      currentIndex = nextIndex;\n    }\n  }\n\n  /**\n   * Checks if pair of heap elements is in correct order.\n   * For MinHeap the first element must be always smaller or equal.\n   * For MaxHeap the first element must be always bigger or equal.\n   *\n   * @param {*} firstElement\n   * @param {*} secondElement\n   * @return {boolean}\n   */\n  /* istanbul ignore next */\n  pairIsInCorrectOrder(firstElement, secondElement) {\n    throw new Error(`\n      You have to implement heap pair comparison method\n      for ${firstElement} and ${secondElement} values.\n    `);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/heap/MaxHeap.js",
    "content": "import Heap from './Heap';\n\nexport default class MaxHeap extends Heap {\n  /**\n   * Checks if pair of heap elements is in correct order.\n   * For MinHeap the first element must be always smaller or equal.\n   * For MaxHeap the first element must be always bigger or equal.\n   *\n   * @param {*} firstElement\n   * @param {*} secondElement\n   * @return {boolean}\n   */\n  pairIsInCorrectOrder(firstElement, secondElement) {\n    return this.compare.greaterThanOrEqual(firstElement, secondElement);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/heap/MaxHeapAdhoc.js",
    "content": "/**\n * The minimalistic (ad hoc) version of a MaxHeap data structure that doesn't have\n * external dependencies and that is easy to copy-paste and use during the\n * coding interview if allowed by the interviewer (since many data\n * structures in JS are missing).\n */\nclass MaxHeapAdhoc {\n  constructor(heap = []) {\n    this.heap = [];\n    heap.forEach(this.add);\n  }\n\n  add(num) {\n    this.heap.push(num);\n    this.heapifyUp();\n  }\n\n  peek() {\n    return this.heap[0];\n  }\n\n  poll() {\n    if (this.heap.length === 0) return undefined;\n    const top = this.heap[0];\n    this.heap[0] = this.heap[this.heap.length - 1];\n    this.heap.pop();\n    this.heapifyDown();\n    return top;\n  }\n\n  isEmpty() {\n    return this.heap.length === 0;\n  }\n\n  toString() {\n    return this.heap.join(',');\n  }\n\n  heapifyUp() {\n    let nodeIndex = this.heap.length - 1;\n    while (nodeIndex > 0) {\n      const parentIndex = this.getParentIndex(nodeIndex);\n      if (this.heap[parentIndex] >= this.heap[nodeIndex]) break;\n      this.swap(parentIndex, nodeIndex);\n      nodeIndex = parentIndex;\n    }\n  }\n\n  heapifyDown() {\n    let nodeIndex = 0;\n\n    while (\n      (\n        this.hasLeftChild(nodeIndex) && this.heap[nodeIndex] < this.leftChild(nodeIndex)\n      )\n      || (\n        this.hasRightChild(nodeIndex) && this.heap[nodeIndex] < this.rightChild(nodeIndex)\n      )\n    ) {\n      const leftIndex = this.getLeftChildIndex(nodeIndex);\n      const rightIndex = this.getRightChildIndex(nodeIndex);\n      const left = this.leftChild(nodeIndex);\n      const right = this.rightChild(nodeIndex);\n\n      if (this.hasLeftChild(nodeIndex) && this.hasRightChild(nodeIndex)) {\n        if (left >= right) {\n          this.swap(leftIndex, nodeIndex);\n          nodeIndex = leftIndex;\n        } else {\n          this.swap(rightIndex, nodeIndex);\n          nodeIndex = rightIndex;\n        }\n      } else if (this.hasLeftChild(nodeIndex)) {\n        this.swap(leftIndex, nodeIndex);\n        nodeIndex = leftIndex;\n      }\n    }\n  }\n\n  getLeftChildIndex(parentIndex) {\n    return (2 * parentIndex) + 1;\n  }\n\n  getRightChildIndex(parentIndex) {\n    return (2 * parentIndex) + 2;\n  }\n\n  getParentIndex(childIndex) {\n    return Math.floor((childIndex - 1) / 2);\n  }\n\n  hasLeftChild(parentIndex) {\n    return this.getLeftChildIndex(parentIndex) < this.heap.length;\n  }\n\n  hasRightChild(parentIndex) {\n    return this.getRightChildIndex(parentIndex) < this.heap.length;\n  }\n\n  leftChild(parentIndex) {\n    return this.heap[this.getLeftChildIndex(parentIndex)];\n  }\n\n  rightChild(parentIndex) {\n    return this.heap[this.getRightChildIndex(parentIndex)];\n  }\n\n  swap(indexOne, indexTwo) {\n    const tmp = this.heap[indexTwo];\n    this.heap[indexTwo] = this.heap[indexOne];\n    this.heap[indexOne] = tmp;\n  }\n}\n\nexport default MaxHeapAdhoc;\n"
  },
  {
    "path": "src/data-structures/heap/MinHeap.js",
    "content": "import Heap from './Heap';\n\nexport default class MinHeap extends Heap {\n  /**\n   * Checks if pair of heap elements is in correct order.\n   * For MinHeap the first element must be always smaller or equal.\n   * For MaxHeap the first element must be always bigger or equal.\n   *\n   * @param {*} firstElement\n   * @param {*} secondElement\n   * @return {boolean}\n   */\n  pairIsInCorrectOrder(firstElement, secondElement) {\n    return this.compare.lessThanOrEqual(firstElement, secondElement);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/heap/MinHeapAdhoc.js",
    "content": "/**\n * The minimalistic (ad hoc) version of a MinHeap data structure that doesn't have\n * external dependencies and that is easy to copy-paste and use during the\n * coding interview if allowed by the interviewer (since many data\n * structures in JS are missing).\n */\nclass MinHeapAdhoc {\n  constructor(heap = []) {\n    this.heap = [];\n    heap.forEach(this.add);\n  }\n\n  add(num) {\n    this.heap.push(num);\n    this.heapifyUp();\n  }\n\n  peek() {\n    return this.heap[0];\n  }\n\n  poll() {\n    if (this.heap.length === 0) return undefined;\n    const top = this.heap[0];\n    this.heap[0] = this.heap[this.heap.length - 1];\n    this.heap.pop();\n    this.heapifyDown();\n    return top;\n  }\n\n  isEmpty() {\n    return this.heap.length === 0;\n  }\n\n  toString() {\n    return this.heap.join(',');\n  }\n\n  heapifyUp() {\n    let nodeIndex = this.heap.length - 1;\n    while (nodeIndex > 0) {\n      const parentIndex = this.getParentIndex(nodeIndex);\n      if (this.heap[parentIndex] <= this.heap[nodeIndex]) break;\n      this.swap(parentIndex, nodeIndex);\n      nodeIndex = parentIndex;\n    }\n  }\n\n  heapifyDown() {\n    let nodeIndex = 0;\n\n    while (\n      (\n        this.hasLeftChild(nodeIndex)\n        && this.heap[nodeIndex] > this.leftChild(nodeIndex)\n      )\n      || (\n        this.hasRightChild(nodeIndex)\n        && this.heap[nodeIndex] > this.rightChild(nodeIndex)\n      )\n    ) {\n      const leftIndex = this.getLeftChildIndex(nodeIndex);\n      const rightIndex = this.getRightChildIndex(nodeIndex);\n      const left = this.leftChild(nodeIndex);\n      const right = this.rightChild(nodeIndex);\n\n      if (this.hasLeftChild(nodeIndex) && this.hasRightChild(nodeIndex)) {\n        if (left <= right) {\n          this.swap(leftIndex, nodeIndex);\n          nodeIndex = leftIndex;\n        } else {\n          this.swap(rightIndex, nodeIndex);\n          nodeIndex = rightIndex;\n        }\n      } else if (this.hasLeftChild(nodeIndex)) {\n        this.swap(leftIndex, nodeIndex);\n        nodeIndex = leftIndex;\n      }\n    }\n  }\n\n  getLeftChildIndex(parentIndex) {\n    return 2 * parentIndex + 1;\n  }\n\n  getRightChildIndex(parentIndex) {\n    return 2 * parentIndex + 2;\n  }\n\n  getParentIndex(childIndex) {\n    return Math.floor((childIndex - 1) / 2);\n  }\n\n  hasLeftChild(parentIndex) {\n    return this.getLeftChildIndex(parentIndex) < this.heap.length;\n  }\n\n  hasRightChild(parentIndex) {\n    return this.getRightChildIndex(parentIndex) < this.heap.length;\n  }\n\n  leftChild(parentIndex) {\n    return this.heap[this.getLeftChildIndex(parentIndex)];\n  }\n\n  rightChild(parentIndex) {\n    return this.heap[this.getRightChildIndex(parentIndex)];\n  }\n\n  swap(indexOne, indexTwo) {\n    const tmp = this.heap[indexTwo];\n    this.heap[indexTwo] = this.heap[indexOne];\n    this.heap[indexOne] = tmp;\n  }\n}\n\nexport default MinHeapAdhoc;\n"
  },
  {
    "path": "src/data-structures/heap/README.fr-FR.md",
    "content": "# Tas (structure de données)\n\nEn informatique, un **tas** est une structure de données arborescente spécialisée qui satisfait la propriété de tas décrite ci-dessous.\n\nDans 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`.\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nDans un *tas maximal* (en anglais *max heap*), la clé de `P` est supérieure ou égale à la clé de `C`.\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\nLe nœud au «sommet» du tas sans parents est appelé le nœud racine.\n\n## Références\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/Tas_(informatique))\n- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/heap/README.ja-JP.md",
    "content": "# ヒープ (データ構造)\n\nコンピュータサイエンスにおいて、*ヒープ*は特殊な木構造のデータ構造で、後述するヒープの特性を持っています。\n\n*最小ヒープ*では、もし`P`が`C`の親ノードの場合、`P`のキー(値)は`C`のキーより小さい、または等しくなります。\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n*最大ヒープ*では、`P`のキーは`C`のキーより大きい、もしくは等しくなります。\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\nヒープの「トップ」のノードには親ノードが存在せず、ルートノードと呼ばれます。\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/heap/README.ko-KR.md",
    "content": "# 힙 (자료구조)\n\n컴퓨터 과학에서의 **힙**은 아래에 설명된 힙 속성을 만족하는 전문화된 트리 기반 데이터구조입니다.\n\n*최소 힙*에서 `P`가 `C`의 상위 노드라면 `P`의 키(값)는 `C`의 키보다 작거나 같습니다.\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n*최대 힙*에서 `P`의 키는 `C`의 키보다 크거나 같습니다.\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\n상위 노드가 없는 힙의 \"상단\"에 있는 노드를 루트 노드라고 합니다.\n\n## 참조\n\n- [Wikipedia](<https://en.wikipedia.org/wiki/Heap_(data_structure)>)\n- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n\n"
  },
  {
    "path": "src/data-structures/heap/README.md",
    "content": "# Heap (data-structure)\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md),\n[_Türkçe_](README.tr-TR.md),\n[_한국어_](README.ko-KR.md),\n[_Українська_](README.uk-UA.md)\n\n\nIn computer science, a **heap** is a specialized tree-based\ndata structure that satisfies the heap property described\nbelow.\n\nIn a *min heap*, if `P` is a parent node of `C`, then the\nkey (the value) of `P` is less than or equal to the\nkey of `C`.\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nIn a *max heap*, the key of `P` is greater than or equal\nto the key of `C`\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\nThe node at the \"top\" of the heap with no parents is\ncalled the root node.\n\n## Time Complexities\n\nHere are time complexities of various heap data structures. Function names assume a max-heap.\n\n| Operation | find-max | delete-max | insert| increase-key| meld |\n| --------- | -------- | ---------- | ----- | ----------- | ---- |\n| [Binary](https://en.wikipedia.org/wiki/Binary_heap) | `Θ(1)` | `Θ(log n)` | `O(log n)` | `O(log n)` | `Θ(n)` |\n| [Leftist](https://en.wikipedia.org/wiki/Leftist_tree) | `Θ(1)` | `Θ(log n)` | `Θ(log n)` | `O(log n)` | `Θ(log n)` |\n| [Binomial](https://en.wikipedia.org/wiki/Binomial_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `O(log n)` | `O(log n)` |\n| [Fibonacci](https://en.wikipedia.org/wiki/Fibonacci_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |\n| [Pairing](https://en.wikipedia.org/wiki/Pairing_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `o(log n)` | `Θ(1)` |\n| [Brodal](https://en.wikipedia.org/wiki/Brodal_queue) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |\n| [Rank-pairing](https://en.wikipedia.org/w/index.php?title=Rank-pairing_heap&action=edit&redlink=1) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |\n| [Strict Fibonacci](https://en.wikipedia.org/wiki/Fibonacci_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |\n| [2-3 heap](https://en.wikipedia.org/wiki/2%E2%80%933_heap) | `O(log n)` | `O(log n)` | `O(log n)` | `Θ(1)` | `?` |\n\nWhere:\n- **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*)\n- **delete-max (or delete-min):** removing the root node of a max heap (or min heap), respectively\n- **insert:** adding a new key to the heap (a.k.a., *push*)\n- **increase-key or decrease-key:** updating a key within a max- or min-heap, respectively\n- **meld:** joining two heaps to form a valid new heap containing all the elements of both, destroying the original heaps.\n\n> In this repository, the [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js) are examples of the **Binary** heap.\n\n## Implementation\n\n- [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js)\n- [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).\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/heap/README.pt-BR.md",
    "content": "# Heap (estrutura de dados)\n\nNa ciência da computação, um **heap** é uma estrutura de dados\nbaseada em uma árvore especializada que satisfaz a propriedade _heap_ descrita abaixo.\n\nEm um *heap mínimo* (min heap), caso `P` é um nó pai de `C`, então a chave\n(o valor) de `P` é menor ou igual a chave de `C`.\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nEm uma *heap máximo* (max heap), a chave de `P` é maior ou igual\na chave de `C`.\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\nO nó no \"topo\" do _heap_, cujo não possui pais, é chamado de nó raiz.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/heap/README.ru-RU.md",
    "content": "# Куча (структура данных)\n\nВ компьютерных науках куча — это специализированная структура данных типа дерево, которая удовлетворяет свойству кучи:\nесли B является узлом-потомком узла A, то ключ(A) ≥ ключ(B). Из этого следует, что элемент с наибольшим ключом всегда\nявляется корневым узлом кучи, поэтому иногда такие кучи называют max-кучами.\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\nЕсли сравнение перевернуть, то наименьший элемент будет всегда корневым узлом, такие кучи называют min-кучами.\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nНе существует никаких ограничений относительно того, сколько узлов-потомков имеет каждый узел кучи. На практике их\nчисло обычно не более двух. Куча является максимально эффективной реализацией абстрактного типа данных, который\nназывается очередью с приоритетом.\n\nУзел на вершине кучи, у которого нет родителей, называется корневым узлом.\n\n## Ссылки\n\n- [Wikipedia](https://ru.wikipedia.org/wiki/Куча_(структура_данных))\n- [YouTube](https://www.youtube.com/watch?v=noQ4SUoqrQA)\n"
  },
  {
    "path": "src/data-structures/heap/README.tr-TR.md",
    "content": "# Heap (data-structure)\n\nBilgisayar biliminde, **yığın (heap)** aşağıda açıklanan özellikleri karşılayan ağaç tabanlı(tree-based) özel bir veri yapısıdır.\n\n*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.\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n*max heap*, `P`'nin anahtarı `C`'nin anahtarından büyük veya eşittir.\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\nYığının (Heap) \"en üstündeki\" ebeveyni olmayan düğüme kök düğüm (root node) denir.\n\n## Referanslar\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/heap/README.uk-UA.md",
    "content": "# Купа (структура даних)\n\nУ комп'ютерних науках купа - це спеціалізована структура даних на кшталт дерева, яка задовольняє властивості купи:\nякщо B є вузлом-нащадком вузла A, то ключ (A) ≥ ключ (B). З цього випливає, що елемент із найбільшим ключем завжди\nє кореневим вузлом купи, тому іноді такі купи називають max-купами.\n\n![MaxHeap](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\nЯкщо порівняння перевернути, то найменший елемент завжди буде кореневим вузлом, такі купи називають min-купами.\n\n![MinHeap](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\nНе існує жодних обмежень щодо того, скільки вузлів-нащадків має кожен вузол купи. На практиці їх\nчисло зазвичай трохи більше двох. Купа є максимально ефективною реалізацією абстрактного типу даних, який\nназивається чергою із пріоритетом.\n\nВузол на вершині купи, який не має батьків, називається кореневим вузлом.\n\n## Посилання\n\n- [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))\n"
  },
  {
    "path": "src/data-structures/heap/README.zh-CN.md",
    "content": "# 堆 (数据结构)\n\n在计算机科学中, 一个 **堆(heap)** 是一种特殊的基于树的数据结构，它满足下面描述的堆属性。\n\n在一个 *最小堆(min heap)* 中, 如果 `P` 是 `C` 的一个父级节点, 那么 `P`  的key(或value)应小于或等于 `C` 的对应值.\n\n![M最小堆](./images/min-heap.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n在一个  *最大堆(max heap)* 中,  `P` 的key(或value)大于 `C` 的对应值。\n\n![堆](./images/max-heap.jpeg)\n\n![Array Representation](./images/array-representation.jpeg)\n\n\n在堆“顶部”的没有父级节点的节点,被称之为根节点。\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/heap/__test__/Heap.test.js",
    "content": "import Heap from '../Heap';\n\ndescribe('Heap', () => {\n  it('should not allow to create instance of the Heap directly', () => {\n    const instantiateHeap = () => {\n      const heap = new Heap();\n      heap.add(5);\n    };\n\n    expect(instantiateHeap).toThrow();\n  });\n});\n"
  },
  {
    "path": "src/data-structures/heap/__test__/MaxHeap.test.js",
    "content": "import MaxHeap from '../MaxHeap';\nimport Comparator from '../../../utils/comparator/Comparator';\n\ndescribe('MaxHeap', () => {\n  it('should create an empty max heap', () => {\n    const maxHeap = new MaxHeap();\n\n    expect(maxHeap).toBeDefined();\n    expect(maxHeap.peek()).toBeNull();\n    expect(maxHeap.isEmpty()).toBe(true);\n  });\n\n  it('should add items to the heap and heapify it up', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(5);\n    expect(maxHeap.isEmpty()).toBe(false);\n    expect(maxHeap.peek()).toBe(5);\n    expect(maxHeap.toString()).toBe('5');\n\n    maxHeap.add(3);\n    expect(maxHeap.peek()).toBe(5);\n    expect(maxHeap.toString()).toBe('5,3');\n\n    maxHeap.add(10);\n    expect(maxHeap.peek()).toBe(10);\n    expect(maxHeap.toString()).toBe('10,3,5');\n\n    maxHeap.add(1);\n    expect(maxHeap.peek()).toBe(10);\n    expect(maxHeap.toString()).toBe('10,3,5,1');\n\n    maxHeap.add(1);\n    expect(maxHeap.peek()).toBe(10);\n    expect(maxHeap.toString()).toBe('10,3,5,1,1');\n\n    expect(maxHeap.poll()).toBe(10);\n    expect(maxHeap.toString()).toBe('5,3,1,1');\n\n    expect(maxHeap.poll()).toBe(5);\n    expect(maxHeap.toString()).toBe('3,1,1');\n\n    expect(maxHeap.poll()).toBe(3);\n    expect(maxHeap.toString()).toBe('1,1');\n  });\n\n  it('should poll items from the heap and heapify it down', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(5);\n    maxHeap.add(3);\n    maxHeap.add(10);\n    maxHeap.add(11);\n    maxHeap.add(1);\n\n    expect(maxHeap.toString()).toBe('11,10,5,3,1');\n\n    expect(maxHeap.poll()).toBe(11);\n    expect(maxHeap.toString()).toBe('10,3,5,1');\n\n    expect(maxHeap.poll()).toBe(10);\n    expect(maxHeap.toString()).toBe('5,3,1');\n\n    expect(maxHeap.poll()).toBe(5);\n    expect(maxHeap.toString()).toBe('3,1');\n\n    expect(maxHeap.poll()).toBe(3);\n    expect(maxHeap.toString()).toBe('1');\n\n    expect(maxHeap.poll()).toBe(1);\n    expect(maxHeap.toString()).toBe('');\n\n    expect(maxHeap.poll()).toBeNull();\n    expect(maxHeap.toString()).toBe('');\n  });\n\n  it('should heapify down through the right branch as well', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(3);\n    maxHeap.add(12);\n    maxHeap.add(10);\n\n    expect(maxHeap.toString()).toBe('12,3,10');\n\n    maxHeap.add(11);\n    expect(maxHeap.toString()).toBe('12,11,10,3');\n\n    expect(maxHeap.poll()).toBe(12);\n    expect(maxHeap.toString()).toBe('11,3,10');\n  });\n\n  it('should be possible to find item indices in heap', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(3);\n    maxHeap.add(12);\n    maxHeap.add(10);\n    maxHeap.add(11);\n    maxHeap.add(11);\n\n    expect(maxHeap.toString()).toBe('12,11,10,3,11');\n\n    expect(maxHeap.find(5)).toEqual([]);\n    expect(maxHeap.find(12)).toEqual([0]);\n    expect(maxHeap.find(11)).toEqual([1, 4]);\n  });\n\n  it('should be possible to remove items from heap with heapify down', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(3);\n    maxHeap.add(12);\n    maxHeap.add(10);\n    maxHeap.add(11);\n    maxHeap.add(11);\n\n    expect(maxHeap.toString()).toBe('12,11,10,3,11');\n\n    expect(maxHeap.remove(12).toString()).toEqual('11,11,10,3');\n    expect(maxHeap.remove(12).peek()).toEqual(11);\n    expect(maxHeap.remove(11).toString()).toEqual('10,3');\n    expect(maxHeap.remove(10).peek()).toEqual(3);\n  });\n\n  it('should be possible to remove items from heap with heapify up', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(3);\n    maxHeap.add(10);\n    maxHeap.add(5);\n    maxHeap.add(6);\n    maxHeap.add(7);\n    maxHeap.add(4);\n    maxHeap.add(6);\n    maxHeap.add(8);\n    maxHeap.add(2);\n    maxHeap.add(1);\n\n    expect(maxHeap.toString()).toBe('10,8,6,7,6,4,5,3,2,1');\n    expect(maxHeap.remove(4).toString()).toEqual('10,8,6,7,6,1,5,3,2');\n    expect(maxHeap.remove(3).toString()).toEqual('10,8,6,7,6,1,5,2');\n    expect(maxHeap.remove(5).toString()).toEqual('10,8,6,7,6,1,2');\n    expect(maxHeap.remove(10).toString()).toEqual('8,7,6,2,6,1');\n    expect(maxHeap.remove(6).toString()).toEqual('8,7,1,2');\n    expect(maxHeap.remove(2).toString()).toEqual('8,7,1');\n    expect(maxHeap.remove(1).toString()).toEqual('8,7');\n    expect(maxHeap.remove(7).toString()).toEqual('8');\n    expect(maxHeap.remove(8).toString()).toEqual('');\n  });\n\n  it('should be possible to remove items from heap with custom finding comparator', () => {\n    const maxHeap = new MaxHeap();\n    maxHeap.add('a');\n    maxHeap.add('bb');\n    maxHeap.add('ccc');\n    maxHeap.add('dddd');\n\n    expect(maxHeap.toString()).toBe('dddd,ccc,bb,a');\n\n    const comparator = new Comparator((a, b) => {\n      if (a.length === b.length) {\n        return 0;\n      }\n\n      return a.length < b.length ? -1 : 1;\n    });\n\n    maxHeap.remove('hey', comparator);\n    expect(maxHeap.toString()).toBe('dddd,a,bb');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/heap/__test__/MaxHeapAdhoc.test.js",
    "content": "import MaxHeap from '../MaxHeapAdhoc';\n\ndescribe('MaxHeapAdhoc', () => {\n  it('should create an empty max heap', () => {\n    const maxHeap = new MaxHeap();\n\n    expect(maxHeap).toBeDefined();\n    expect(maxHeap.peek()).toBe(undefined);\n    expect(maxHeap.isEmpty()).toBe(true);\n  });\n\n  it('should add items to the heap and heapify it up', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(5);\n    expect(maxHeap.isEmpty()).toBe(false);\n    expect(maxHeap.peek()).toBe(5);\n    expect(maxHeap.toString()).toBe('5');\n\n    maxHeap.add(3);\n    expect(maxHeap.peek()).toBe(5);\n    expect(maxHeap.toString()).toBe('5,3');\n\n    maxHeap.add(10);\n    expect(maxHeap.peek()).toBe(10);\n    expect(maxHeap.toString()).toBe('10,3,5');\n\n    maxHeap.add(1);\n    expect(maxHeap.peek()).toBe(10);\n    expect(maxHeap.toString()).toBe('10,3,5,1');\n\n    maxHeap.add(1);\n    expect(maxHeap.peek()).toBe(10);\n    expect(maxHeap.toString()).toBe('10,3,5,1,1');\n\n    expect(maxHeap.poll()).toBe(10);\n    expect(maxHeap.toString()).toBe('5,3,1,1');\n\n    expect(maxHeap.poll()).toBe(5);\n    expect(maxHeap.toString()).toBe('3,1,1');\n\n    expect(maxHeap.poll()).toBe(3);\n    expect(maxHeap.toString()).toBe('1,1');\n  });\n\n  it('should poll items from the heap and heapify it down', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(5);\n    maxHeap.add(3);\n    maxHeap.add(10);\n    maxHeap.add(11);\n    maxHeap.add(1);\n\n    expect(maxHeap.toString()).toBe('11,10,5,3,1');\n\n    expect(maxHeap.poll()).toBe(11);\n    expect(maxHeap.toString()).toBe('10,3,5,1');\n\n    expect(maxHeap.poll()).toBe(10);\n    expect(maxHeap.toString()).toBe('5,3,1');\n\n    expect(maxHeap.poll()).toBe(5);\n    expect(maxHeap.toString()).toBe('3,1');\n\n    expect(maxHeap.poll()).toBe(3);\n    expect(maxHeap.toString()).toBe('1');\n\n    expect(maxHeap.poll()).toBe(1);\n    expect(maxHeap.toString()).toBe('');\n\n    expect(maxHeap.poll()).toBe(undefined);\n    expect(maxHeap.toString()).toBe('');\n  });\n\n  it('should heapify down through the right branch as well', () => {\n    const maxHeap = new MaxHeap();\n\n    maxHeap.add(3);\n    maxHeap.add(12);\n    maxHeap.add(10);\n\n    expect(maxHeap.toString()).toBe('12,3,10');\n\n    maxHeap.add(11);\n    expect(maxHeap.toString()).toBe('12,11,10,3');\n\n    expect(maxHeap.poll()).toBe(12);\n    expect(maxHeap.toString()).toBe('11,3,10');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/heap/__test__/MinHeap.test.js",
    "content": "import MinHeap from '../MinHeap';\nimport Comparator from '../../../utils/comparator/Comparator';\n\ndescribe('MinHeap', () => {\n  it('should create an empty min heap', () => {\n    const minHeap = new MinHeap();\n\n    expect(minHeap).toBeDefined();\n    expect(minHeap.peek()).toBeNull();\n    expect(minHeap.isEmpty()).toBe(true);\n  });\n\n  it('should add items to the heap and heapify it up', () => {\n    const minHeap = new MinHeap();\n\n    minHeap.add(5);\n    expect(minHeap.isEmpty()).toBe(false);\n    expect(minHeap.peek()).toBe(5);\n    expect(minHeap.toString()).toBe('5');\n\n    minHeap.add(3);\n    expect(minHeap.peek()).toBe(3);\n    expect(minHeap.toString()).toBe('3,5');\n\n    minHeap.add(10);\n    expect(minHeap.peek()).toBe(3);\n    expect(minHeap.toString()).toBe('3,5,10');\n\n    minHeap.add(1);\n    expect(minHeap.peek()).toBe(1);\n    expect(minHeap.toString()).toBe('1,3,10,5');\n\n    minHeap.add(1);\n    expect(minHeap.peek()).toBe(1);\n    expect(minHeap.toString()).toBe('1,1,10,5,3');\n\n    expect(minHeap.poll()).toBe(1);\n    expect(minHeap.toString()).toBe('1,3,10,5');\n\n    expect(minHeap.poll()).toBe(1);\n    expect(minHeap.toString()).toBe('3,5,10');\n\n    expect(minHeap.poll()).toBe(3);\n    expect(minHeap.toString()).toBe('5,10');\n  });\n\n  it('should poll items from the heap and heapify it down', () => {\n    const minHeap = new MinHeap();\n\n    minHeap.add(5);\n    minHeap.add(3);\n    minHeap.add(10);\n    minHeap.add(11);\n    minHeap.add(1);\n\n    expect(minHeap.toString()).toBe('1,3,10,11,5');\n\n    expect(minHeap.poll()).toBe(1);\n    expect(minHeap.toString()).toBe('3,5,10,11');\n\n    expect(minHeap.poll()).toBe(3);\n    expect(minHeap.toString()).toBe('5,11,10');\n\n    expect(minHeap.poll()).toBe(5);\n    expect(minHeap.toString()).toBe('10,11');\n\n    expect(minHeap.poll()).toBe(10);\n    expect(minHeap.toString()).toBe('11');\n\n    expect(minHeap.poll()).toBe(11);\n    expect(minHeap.toString()).toBe('');\n\n    expect(minHeap.poll()).toBeNull();\n    expect(minHeap.toString()).toBe('');\n  });\n\n  it('should heapify down through the right branch as well', () => {\n    const minHeap = new MinHeap();\n\n    minHeap.add(3);\n    minHeap.add(12);\n    minHeap.add(10);\n\n    expect(minHeap.toString()).toBe('3,12,10');\n\n    minHeap.add(11);\n    expect(minHeap.toString()).toBe('3,11,10,12');\n\n    expect(minHeap.poll()).toBe(3);\n    expect(minHeap.toString()).toBe('10,11,12');\n  });\n\n  it('should be possible to find item indices in heap', () => {\n    const minHeap = new MinHeap();\n\n    minHeap.add(3);\n    minHeap.add(12);\n    minHeap.add(10);\n    minHeap.add(11);\n    minHeap.add(11);\n\n    expect(minHeap.toString()).toBe('3,11,10,12,11');\n\n    expect(minHeap.find(5)).toEqual([]);\n    expect(minHeap.find(3)).toEqual([0]);\n    expect(minHeap.find(11)).toEqual([1, 4]);\n  });\n\n  it('should be possible to remove items from heap with heapify down', () => {\n    const minHeap = new MinHeap();\n\n    minHeap.add(3);\n    minHeap.add(12);\n    minHeap.add(10);\n    minHeap.add(11);\n    minHeap.add(11);\n\n    expect(minHeap.toString()).toBe('3,11,10,12,11');\n\n    expect(minHeap.remove(3).toString()).toEqual('10,11,11,12');\n    expect(minHeap.remove(3).peek()).toEqual(10);\n    expect(minHeap.remove(11).toString()).toEqual('10,12');\n    expect(minHeap.remove(3).peek()).toEqual(10);\n  });\n\n  it('should be possible to remove items from heap with heapify up', () => {\n    const minHeap = new MinHeap();\n\n    minHeap.add(3);\n    minHeap.add(10);\n    minHeap.add(5);\n    minHeap.add(6);\n    minHeap.add(7);\n    minHeap.add(4);\n    minHeap.add(6);\n    minHeap.add(8);\n    minHeap.add(2);\n    minHeap.add(1);\n\n    expect(minHeap.toString()).toBe('1,2,4,6,3,5,6,10,8,7');\n    expect(minHeap.remove(8).toString()).toEqual('1,2,4,6,3,5,6,10,7');\n    expect(minHeap.remove(7).toString()).toEqual('1,2,4,6,3,5,6,10');\n    expect(minHeap.remove(1).toString()).toEqual('2,3,4,6,10,5,6');\n    expect(minHeap.remove(2).toString()).toEqual('3,6,4,6,10,5');\n    expect(minHeap.remove(6).toString()).toEqual('3,5,4,10');\n    expect(minHeap.remove(10).toString()).toEqual('3,5,4');\n    expect(minHeap.remove(5).toString()).toEqual('3,4');\n    expect(minHeap.remove(3).toString()).toEqual('4');\n    expect(minHeap.remove(4).toString()).toEqual('');\n  });\n\n  it('should be possible to remove items from heap with custom finding comparator', () => {\n    const minHeap = new MinHeap();\n    minHeap.add('dddd');\n    minHeap.add('ccc');\n    minHeap.add('bb');\n    minHeap.add('a');\n\n    expect(minHeap.toString()).toBe('a,bb,ccc,dddd');\n\n    const comparator = new Comparator((a, b) => {\n      if (a.length === b.length) {\n        return 0;\n      }\n\n      return a.length < b.length ? -1 : 1;\n    });\n\n    minHeap.remove('hey', comparator);\n    expect(minHeap.toString()).toBe('a,bb,dddd');\n  });\n\n  it('should remove values from heap and correctly re-order the tree', () => {\n    const minHeap = new MinHeap();\n\n    minHeap.add(1);\n    minHeap.add(2);\n    minHeap.add(3);\n    minHeap.add(4);\n    minHeap.add(5);\n    minHeap.add(6);\n    minHeap.add(7);\n    minHeap.add(8);\n    minHeap.add(9);\n\n    expect(minHeap.toString()).toBe('1,2,3,4,5,6,7,8,9');\n\n    minHeap.remove(2);\n    expect(minHeap.toString()).toBe('1,4,3,8,5,6,7,9');\n\n    minHeap.remove(4);\n    expect(minHeap.toString()).toBe('1,5,3,8,9,6,7');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/heap/__test__/MinHeapAdhoc.test.js",
    "content": "import MinHeapAdhoc from '../MinHeapAdhoc';\n\ndescribe('MinHeapAdhoc', () => {\n  it('should create an empty min heap', () => {\n    const minHeap = new MinHeapAdhoc();\n\n    expect(minHeap).toBeDefined();\n    expect(minHeap.peek()).toBe(undefined);\n    expect(minHeap.isEmpty()).toBe(true);\n  });\n\n  it('should add items to the heap and heapify it up', () => {\n    const minHeap = new MinHeapAdhoc();\n\n    minHeap.add(5);\n    expect(minHeap.isEmpty()).toBe(false);\n    expect(minHeap.peek()).toBe(5);\n    expect(minHeap.toString()).toBe('5');\n\n    minHeap.add(3);\n    expect(minHeap.peek()).toBe(3);\n    expect(minHeap.toString()).toBe('3,5');\n\n    minHeap.add(10);\n    expect(minHeap.peek()).toBe(3);\n    expect(minHeap.toString()).toBe('3,5,10');\n\n    minHeap.add(1);\n    expect(minHeap.peek()).toBe(1);\n    expect(minHeap.toString()).toBe('1,3,10,5');\n\n    minHeap.add(1);\n    expect(minHeap.peek()).toBe(1);\n    expect(minHeap.toString()).toBe('1,1,10,5,3');\n\n    expect(minHeap.poll()).toBe(1);\n    expect(minHeap.toString()).toBe('1,3,10,5');\n\n    expect(minHeap.poll()).toBe(1);\n    expect(minHeap.toString()).toBe('3,5,10');\n\n    expect(minHeap.poll()).toBe(3);\n    expect(minHeap.toString()).toBe('5,10');\n  });\n\n  it('should poll items from the heap and heapify it down', () => {\n    const minHeap = new MinHeapAdhoc();\n\n    minHeap.add(5);\n    minHeap.add(3);\n    minHeap.add(10);\n    minHeap.add(11);\n    minHeap.add(1);\n\n    expect(minHeap.toString()).toBe('1,3,10,11,5');\n\n    expect(minHeap.poll()).toBe(1);\n    expect(minHeap.toString()).toBe('3,5,10,11');\n\n    expect(minHeap.poll()).toBe(3);\n    expect(minHeap.toString()).toBe('5,11,10');\n\n    expect(minHeap.poll()).toBe(5);\n    expect(minHeap.toString()).toBe('10,11');\n\n    expect(minHeap.poll()).toBe(10);\n    expect(minHeap.toString()).toBe('11');\n\n    expect(minHeap.poll()).toBe(11);\n    expect(minHeap.toString()).toBe('');\n\n    expect(minHeap.poll()).toBe(undefined);\n    expect(minHeap.toString()).toBe('');\n  });\n\n  it('should heapify down through the right branch as well', () => {\n    const minHeap = new MinHeapAdhoc();\n\n    minHeap.add(3);\n    minHeap.add(12);\n    minHeap.add(10);\n\n    expect(minHeap.toString()).toBe('3,12,10');\n\n    minHeap.add(11);\n    expect(minHeap.toString()).toBe('3,11,10,12');\n\n    expect(minHeap.poll()).toBe(3);\n    expect(minHeap.toString()).toBe('10,11,12');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/linked-list/LinkedList.js",
    "content": "import LinkedListNode from './LinkedListNode';\nimport Comparator from '../../utils/comparator/Comparator';\n\nexport default class LinkedList {\n  /**\n   * @param {Function} [comparatorFunction]\n   */\n  constructor(comparatorFunction) {\n    /** @var LinkedListNode */\n    this.head = null;\n\n    /** @var LinkedListNode */\n    this.tail = null;\n\n    this.compare = new Comparator(comparatorFunction);\n  }\n\n  /**\n   * @param {*} value\n   * @return {LinkedList}\n   */\n  prepend(value) {\n    // Make new node to be a head.\n    const newNode = new LinkedListNode(value, this.head);\n    this.head = newNode;\n\n    // If there is no tail yet let's make new node a tail.\n    if (!this.tail) {\n      this.tail = newNode;\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {*} value\n   * @return {LinkedList}\n   */\n  append(value) {\n    const newNode = new LinkedListNode(value);\n\n    // If there is no head yet let's make new node a head.\n    if (!this.head) {\n      this.head = newNode;\n      this.tail = newNode;\n\n      return this;\n    }\n\n    // Attach new node to the end of linked list.\n    this.tail.next = newNode;\n    this.tail = newNode;\n\n    return this;\n  }\n\n  /**\n   * @param {*} value\n   * @param {number} index\n   * @return {LinkedList}\n   */\n  insert(value, rawIndex) {\n    const index = rawIndex < 0 ? 0 : rawIndex;\n    if (index === 0) {\n      this.prepend(value);\n    } else {\n      let count = 1;\n      let currentNode = this.head;\n      const newNode = new LinkedListNode(value);\n      while (currentNode) {\n        if (count === index) break;\n        currentNode = currentNode.next;\n        count += 1;\n      }\n      if (currentNode) {\n        newNode.next = currentNode.next;\n        currentNode.next = newNode;\n      } else {\n        if (this.tail) {\n          this.tail.next = newNode;\n          this.tail = newNode;\n        } else {\n          this.head = newNode;\n          this.tail = newNode;\n        }\n      }\n    }\n    return this;\n  }\n\n  /**\n   * @param {*} value\n   * @return {LinkedListNode}\n   */\n  delete(value) {\n    if (!this.head) {\n      return null;\n    }\n\n    let deletedNode = null;\n\n    // If the head must be deleted then make next node that is different\n    // from the head to be a new head.\n    while (this.head && this.compare.equal(this.head.value, value)) {\n      deletedNode = this.head;\n      this.head = this.head.next;\n    }\n\n    let currentNode = this.head;\n\n    if (currentNode !== null) {\n      // If next node must be deleted then make next node to be a next next one.\n      while (currentNode.next) {\n        if (this.compare.equal(currentNode.next.value, value)) {\n          deletedNode = currentNode.next;\n          currentNode.next = currentNode.next.next;\n        } else {\n          currentNode = currentNode.next;\n        }\n      }\n    }\n\n    // Check if tail must be deleted.\n    if (this.compare.equal(this.tail.value, value)) {\n      this.tail = currentNode;\n    }\n\n    return deletedNode;\n  }\n\n  /**\n   * @param {Object} findParams\n   * @param {*} findParams.value\n   * @param {function} [findParams.callback]\n   * @return {LinkedListNode}\n   */\n  find({ value = undefined, callback = undefined }) {\n    if (!this.head) {\n      return null;\n    }\n\n    let currentNode = this.head;\n\n    while (currentNode) {\n      // If callback is specified then try to find node by callback.\n      if (callback && callback(currentNode.value)) {\n        return currentNode;\n      }\n\n      // If value is specified then try to compare by value..\n      if (value !== undefined && this.compare.equal(currentNode.value, value)) {\n        return currentNode;\n      }\n\n      currentNode = currentNode.next;\n    }\n\n    return null;\n  }\n\n  /**\n   * @return {LinkedListNode}\n   */\n  deleteTail() {\n    const deletedTail = this.tail;\n\n    if (this.head === this.tail) {\n      // There is only one node in linked list.\n      this.head = null;\n      this.tail = null;\n\n      return deletedTail;\n    }\n\n    // If there are many nodes in linked list...\n\n    // Rewind to the last node and delete \"next\" link for the node before the last one.\n    let currentNode = this.head;\n    while (currentNode.next) {\n      if (!currentNode.next.next) {\n        currentNode.next = null;\n      } else {\n        currentNode = currentNode.next;\n      }\n    }\n\n    this.tail = currentNode;\n\n    return deletedTail;\n  }\n\n  /**\n   * @return {LinkedListNode}\n   */\n  deleteHead() {\n    if (!this.head) {\n      return null;\n    }\n\n    const deletedHead = this.head;\n\n    if (this.head.next) {\n      this.head = this.head.next;\n    } else {\n      this.head = null;\n      this.tail = null;\n    }\n\n    return deletedHead;\n  }\n\n  /**\n   * @param {*[]} values - Array of values that need to be converted to linked list.\n   * @return {LinkedList}\n   */\n  fromArray(values) {\n    values.forEach((value) => this.append(value));\n\n    return this;\n  }\n\n  /**\n   * @return {LinkedListNode[]}\n   */\n  toArray() {\n    const nodes = [];\n\n    let currentNode = this.head;\n    while (currentNode) {\n      nodes.push(currentNode);\n      currentNode = currentNode.next;\n    }\n\n    return nodes;\n  }\n\n  /**\n   * @param {function} [callback]\n   * @return {string}\n   */\n  toString(callback) {\n    return this.toArray().map((node) => node.toString(callback)).toString();\n  }\n\n  /**\n   * Reverse a linked list.\n   * @returns {LinkedList}\n   */\n  reverse() {\n    let currNode = this.head;\n    let prevNode = null;\n    let nextNode = null;\n\n    while (currNode) {\n      // Store next node.\n      nextNode = currNode.next;\n\n      // Change next node of the current node so it would link to previous node.\n      currNode.next = prevNode;\n\n      // Move prevNode and currNode nodes one step forward.\n      prevNode = currNode;\n      currNode = nextNode;\n    }\n\n    // Reset head and tail.\n    this.tail = this.head;\n    this.head = prevNode;\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/linked-list/LinkedListNode.js",
    "content": "export default class LinkedListNode {\n  constructor(value, next = null) {\n    this.value = value;\n    this.next = next;\n  }\n\n  toString(callback) {\n    return callback ? callback(this.value) : `${this.value}`;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/linked-list/README.es-ES.md",
    "content": "# Lista Enlazada (Linked List)\n\n_Lee este artículo en otros idiomas:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md)\n[_English_](README.md)\n\nEn ciencias de la computación una **lista enlazada** es una  colección lineal \nde elementos, en los cuales el orden lineal no es dado por\nsu posición física en memoria. En cambio, cada \nelemento señala al siguiente. Es una estructura de datos\nque consiste en un grupo de nodos los cuales juntos representan\nuna secuencia. En su forma más sencilla, cada nodo está\ncompuesto de datos y una referencia (en otras palabras,\nun enlace) al siguiente nodo en la secuencia. Esta estructura\npermite la inserción o eliminación de elementos\ndesde cualquier posición en la secuencia durante la iteración.\nLas variantes más complejas agregan enlaces adicionales, permitiendo\nuna eficiente inserción o eliminación desde referencias arbitrarias\ndel elemento. Una desventaja de las listas enlazadas es que el tiempo de\nacceso es lineal (y difícil de canalizar). Un acceso\nmás rápido, como un acceso aleatorio, no es factible. Los arreglos\ntienen una mejor localización en caché comparados con las listas enlazadas.\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Pseudocódigo para operaciones básicas\n\n### Insertar\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: value is the value to add to the list\n Post: value has been placed at the head of the list\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### Buscar\n\n```text\nContains(head, value)\n  Pre: head is the head node in the list\n       value is the value to search for\n  Post: the item is either in the linked list, true; otherwise false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### Borrar\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true, otherwise false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Atravesar\n\n```text\nTraverse(head)\n  Pre: head is the head node in the list\n  Post: the items in the list have been traversed\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### Atravesar en Reversa\n\n```text\nReverseTraversal(head, tail)\n  Pre: head and tail belong to the same list\n  Post: the items in the list have been traversed in reverse order\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## Complejidades\n\n### Complejidad de Tiempo\n\n| Acceso | Búsqueda | Inserción | Eliminación |\n| :----: | :------: | :-------: | :---------: |\n|  O(n)  |   O(n)   |   O(1)    |    O(n)     |\n\n### Complejidad Espacial\n\nO(n)\n\n## Referencias\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.ja-JP.md",
    "content": "# リンクリスト\n\nコンピュータサイエンスにおいて、**リンクリスト**はデータ要素の線形コレクションです。要素の順番はメモリ内の物理的な配置によっては決まりません。代わりに、各要素が次の要素を指しています。リンクリストはノードのグループからなるデータ構造です。最も単純な形式では、各ノードはデータとシーケンス内における次のノードへの参照(つまり、リンク)で構成されています。この構造はイテレーションにおいて任意の位置へ要素を効率的に挿入、削除することを可能にしています。より複雑なリンクリストではリンクをさらに追加することで、任意の要素の参照から要素を効率的に挿入、削除することを可能にしています。リンクリストの欠点はアクセスタイムが線形である(そして、パイプライン処理が難しい)ことです。ランダムアクセスのような高速なアクセスは実現不可能です。配列の方がリンクリストと比較して参照の局所性が優れています。\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 基本操作の擬似コード\n\n### 挿入\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: value is the value to add to the list\n Post: value has been placed at the head of the list\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### 検索\n\n```text\nContains(head, value)\n  Pre: head is the head node in the list\n       value is the value to search for\n  Post: the item is either in the linked list, true; otherwise false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### 削除\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true, otherwise false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### トラバース\n\n```text\nTraverse(head)\n  Pre: head is the head node in the list\n  Post: the items in the list have been traversed\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### 逆トラバース\n\n```text\nReverseTraversal(head, tail)\n  Pre: head and tail belong to the same list\n  Post: the items in the list have been traversed in reverse order\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## 計算量\n\n### 時間計算量\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(n)      |\n\n### 空間計算量\n\nO(n)\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.ko-KR.md",
    "content": "# 링크드 리스트\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md)\n\n컴퓨터과학에서, **링크드 리스트**는 데이터 요소의 선형 집합이며, 이 집합에서 논리적 저장 순서는 메모리의 물리적 저장 순서와 일치하지 않습니다. 그 대신, 각각의 원소들은 자기 자신 다음의 원소를 가리킵니다. **링크드 리스트**는 순서를 표현하는 노드들의 집합으로 이루어져 있습니다. 간단하게, 각각의 노드들은 데이터와 다음 순서의 노드를 가리키는 레퍼런스로 이루어져 있습니다. (링크라고 부릅니다.) 이 자료구조는 순회하는 동안 순서에 상관없이 효율적인 삽입이나 삭제가 가능합니다. 더 복잡한 변형은 추가적인 링크를 더해, 임의의 원소 참조로부터 효율적인 삽입과 삭제를 가능하게 합니다. 링크드 리스트의 단점은 접근 시간이 선형이라는 것이고, 병렬처리도 하지 못합니다. 임의 접근처럼 빠른 접근은 불가능합니다. 링크드 리스트에 비해 배열이 더 나은 캐시 지역성을 가지고 있습니다.\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 기본 연산에 대한 수도코드\n\n### 삽입\n\n```text\nAdd(value)\n  Pre: 리스트에 추가할 값\n  Post: 리스트의 맨 마지막에 있는 값\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: 리스트에 추가할 값\n Post: 리스트의 맨 앞에 있는 값\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### 탐색\n\n```text\nContains(head, value)\n  Pre: head는 리스트에서 맨 앞 노드\n       value는 찾고자 하는 값\n  Post: 항목이 링크드 리스트에 있으면 true;\n        없으면 false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### 삭제\n\n```text\nRemove(head, value)\n  Pre: head는 리스트에서 맨 앞 노드\n       value는 삭제하고자 하는 값\n  Post: 항목이 링크드 리스트에서 삭제되면 true;\n        없으면 false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### 순회\n\n```text\nTraverse(head)\n  Pre: head는 리스트에서 맨 앞 노드\n  Post: 순회된 항목들\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### 역순회\n\n```text\nReverseTraversal(head, tail)\n  Pre: 같은 리스트에 들어 있는 맨 앞, 맨 뒤 노드\n  Post: 역순회된 항목들\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## 복잡도\n\n### 시간 복잡도\n\n|  접근   |  탐색   |  삽입   |  삭제   |\n| :---: | :---: | :---: | :---: |\n| O(n)  | O(n)  | O(1)  | O(n)  |\n\n### 공간 복잡도\n\nO(n)\n\n## 참조\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.md",
    "content": "# Linked List\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Español_](README.es-ES.md),\n[_Türkçe_](README.tr-TR.md),\n[_Українська_](README.uk-UA.md)\n\nIn computer science, a **linked list** is a linear collection\nof data elements, in which linear order is not given by\ntheir physical placement in memory. Instead, each\nelement points to the next. It is a data structure\nconsisting of a group of nodes which together represent\na sequence. Under the simplest form, each node is\ncomposed of data and a reference (in other words,\na link) to the next node in the sequence. This structure\nallows for efficient insertion or removal of elements\nfrom any position in the sequence during iteration.\nMore complex variants add additional links, allowing\nefficient insertion or removal from arbitrary element\nreferences. A drawback of linked lists is that access\ntime is linear (and difficult to pipeline). Faster\naccess, such as random access, is not feasible. Arrays\nhave better cache locality as compared to linked lists.\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Pseudocode for Basic Operations\n\n### Insert\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: value is the value to add to the list\n Post: value has been placed at the head of the list\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### Search\n\n```text\nContains(head, value)\n  Pre: head is the head node in the list\n       value is the value to search for\n  Post: the item is either in the linked list, true; otherwise false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### Delete\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true, otherwise false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n      tail.next = null\n    else\n      n.next ← n.next.next\n    end if\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Traverse\n\n```text\nTraverse(head)\n  Pre: head is the head node in the list\n  Post: the items in the list have been traversed\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### Traverse in Reverse\n\n```text\nReverseTraversal(head, tail)\n  Pre: head and tail belong to the same list\n  Post: the items in the list have been traversed in reverse order\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## Complexities\n\n### Time Complexity\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(n)      |\n\n### Space Complexity\n\nO(n)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.pt-BR.md",
    "content": "# Lista Encadeada (Linked List)\n\nNa ciência da computação, uma **lista encadeada** é uma coleção linear de\nelementos de dados, em que a ordem linear não é dada por sua locação\nfísica na memória. Em vez disso, cada elemento aponta para o próximo.\nÉ uma estrutura de dados consistindo em um grupo de nós\nque juntos representam uma sequência. Sob a forma mais simples,\ncada nó é composto de dados e uma referência (em outras palavras,\numa ligação/conexão) para o próximo nó na sequência. Esta estrutura\npermite inserção ou remoção eficiente de elementos de qualquer\nposição na sequência durante a iteração.\n\nVariantes mais complexas adicionam ligações adicionais, permitindo\numa inserção ou remoção mais eficiente a partir de referências\nde elementos arbitrárias. Uma desvantagem das listas encadeadas\né que o tempo de acesso é linear (e difícil de inserir em uma\npipeline). Acesso mais rápido, como acesso aleatório, não é viável.\nArrays possuem uma melhor localização de cache em comparação\ncom listas encadeadas (linked lists).\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Pseudo código para Operações Básicas\n\n### Inserção\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: value is the value to add to the list\n Post: value has been placed at the head of the list\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### Pesquisa\n\n```text\nContains(head, value)\n  Pre: head is the head node in the list\n       value is the value to search for\n  Post: the item is either in the linked list, true; otherwise false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### Remoção\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true, otherwise false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Travessia\n\n```text\nTraverse(head)\n  Pre: head is the head node in the list\n  Post: the items in the list have been traversed\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### Travessia Reversa\n\n```text\nReverseTraversal(head, tail)\n  Pre: head and tail belong to the same list\n  Post: the items in the list have been traversed in reverse order\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## Complexidades\n\n### Complexidade de Tempo\n\n| Acesso | Pesquisa | Inserção | Remoção |\n| :----: | :------: | :------: | :-----: |\n|  O(n)  |  O(n)    |  O(1)    |  O(n)   |\n\n### Complexidade de Espaçø\n\nO(n)\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.ru-RU.md",
    "content": "# Связный список\n\nСвязный список — базовая динамическая структура данных в информатике, состоящая из узлов, каждый из которых содержит как собственно данные,так ссылку («связку») на следующий узел списка. Данная структура позволяет эффективно добавлять и удалять элементы на произвольной позиции в последовательности в процессе итерации. Более сложные варианты включают дополнительные ссылки, позволяющие эффективно добавлять и удалять произвольные элементы.\n\nПринципиальным преимуществом перед массивом является структурная гибкость: порядок элементов связного списка может не совпадать с порядком расположения элементов данных в памяти компьютера, а порядок обхода списка всегда явно задаётся его внутренними связями. Суть преимущества состоит в том, что во многих языках создание массива требует указать его размер заранее. Связный список позволяет обойти это ограничение.\n\nНедостатком связных списков является то, что время доступа линейно (и затруднительно для реализации конвейеров). Быстрый доступ(случайный) невозможен.\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Псевдокод основных операций\n\n### Вставка\n\n```text\nAdd(value)\n  Pre: value - добавляемое значение\n  Post: value помещено в конец списка\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: value - добавляемое значение\n Post: value помещено в начало списка\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### Поиск\n\n```text\nContains(head, value)\n  Pre: head - первый узел в списке\n         value - значение, которое следует найти\n  Post: true - value найдено в списке, иначе false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### Удаление\n\n```text\nRemove(head, value)\n  Pre: head - первый узел в списке\n       value - значение, которое следует удалить\n  Post: true - value удалено из списка, иначе false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Обход\n\n```text\nTraverse(head)\n  Pre: head - первый узел в списке\n  Post: элементы списка пройдены\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### Обратный обход\n\n```text\nReverseTraversal(head, tail)\n  Pre: head и tail относятся к одному списку\n  Post: элементы списка пройдены в обратном порядке\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## Сложность\n\n### Временная сложность\n\n| Чтение    | Поиск     | Вставка   | Удаление  |\n| :--------: | :-------: | :--------: | :-------: |\n| O(n)       | O(n)      | O(1)       | O(n)      |\n\n### Пространственная сложность\n\nO(n)\n\n## Ссылки\n\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)\n- [YouTube](https://www.youtube.com/watch?v=KTpOalDwBjg)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.tr-TR.md",
    "content": "# Bağlantılı Liste\n\n_Bunu diğer dillerde okuyun:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Español_](README.es-ES.md),\n\nBilgisayar bilimlerinde, **Bağlantılı liste**, her biri hem gerçek verileri\nhem de listedeki bir sonraki düğümün bir bağlantısını içeren dinamik bir\nveri yapısıdır. Bu yapı, yineleme sırasında rastgele bir konumda\nöğeleri verimli bir şekilde eklemenize ve kaldırmanıza olanak tanır.\nDaha karmaşık seçenekler için, isteğe bağlı öğeleri verimli bir şekilde\neklemek ve kaldırmak için ek bağlantılar içerir.\n\nBağlantılı listelerin bir dezavantajı, erişim süresinin doğrusal olmasıdır\n(ve ardışık düzene geçirilmesi zordur). Rastgele erişim gibi daha hızlı erişim\nmümkün değildir. Diziler, bağlantılı listelere kıyasla daha iyi önbellek konumuna sahiptir.\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Temel İşlemler için Sözde Kod\n\n### Ekleme\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: value is the value to add to the list\n Post: value has been placed at the head of the list\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### Arama\n\n```text\nContains(head, value)\n  Pre: head is the head node in the list\n       value is the value to search for\n  Post: the item is either in the linked list, true; otherwise false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### Silme\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true, otherwise false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n      tail.next = null\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Geçiş\n\n```text\nTraverse(head)\n  Pre: head is the head node in the list\n  Post: the items in the list have been traversed\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### Ters Geçiş\n\n```text\nReverseTraversal(head, tail)\n  Pre: head and tail belong to the same list\n  Post: the items in the list have been traversed in reverse order\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## Karmaşıklıklar\n\n### Zaman Karmaşıklığı\n\n| Erişim    | Arama     | Ekleme    | Silme     |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(n)      |\n\n### Uzay Karmaşıklığı\n\nO(n)\n\n## Referanslar\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.uk-UA.md",
    "content": "# Зв'язаний список\n\nЗв'язаний список — базова динамічна структура даних в інформатиці, що складається з вузлів, кожен з яких містить як дані, так і посилання («зв'язку») на наступний вузол списку. Ця структура даних дозволяє ефективно додавати та видаляти елементи на довільній позиції у послідовності у процесі ітерації. Більш складні варіанти включають додаткові посилання, що дозволяють ефективно додавати та видаляти довільні елементи.\n\nПринциповою перевагою перед масивом є структурна гнучкість: порядок елементів зв'язаного списку може збігатися з порядком розташування елементів даних у пам'яті комп'ютера, а порядок обходу списку завжди явно задається його внутрішніми зв'язками. Це важливо, бо у багатьох мовах створення масиву вимагає вказати його розмір заздалегідь. Зв'язаний список дозволяє обійти це обмеження.\n\nНедоліком зв'язаних списків є те, що час доступу є лінійним (і важко для реалізації конвеєрів). Неможливий швидкий доступ (випадковий).\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Псевдокод основних операцій\n\n### Вставка\n\n```text\nAdd(value)\n  Pre: value - значення, що додається\n  Post: value додано в кінець списку\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```text\nPrepend(value)\n Pre: value - значення, що додається\n Post: value додано на початку списку\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### Пошук\n\n```text\nContains(head, value)\n  Pre: head - перший вузол у списку\n         value - значення, яке слід знайти\n  Post: true - value знайдено у списку, інакше false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### Видалення\n\n```text\nRemove(head, value)\n  Pre: head - перший вузол у списку\n       value - значення, яке слід видалити\n  Post: true - value видалено зі списку, інакше false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Обхід\n\n```text\nTraverse(head)\n  Pre: head - перший вузол у списку\n  Post: елементи списку пройдені\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### Зворотній обхід\n\n```text\nReverseTraversal(head, tail)\n  Pre: head і tail відносяться до одного списку\n  Post: елементи списку пройдено у зворотньому порядку\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## Складність\n\n### Часова складність\n\n| Читання    | Пошук     | Вставка    | Вилучення |\n| :--------: | :-------: | :--------: | :-------: |\n| O(n)       | O(n)      | O(1)       | O(n)      |\n\n### Просторова складність\n\nO(n)\n\n## Посилання\n\n- [Wikipedia](https://uk.wikipedia.org/wiki/Зв'язаний_список)\n- [YouTube](https://www.youtube.com/watch?v=6snsMa4E1Os)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.vi-VN.md",
    "content": "# Danh sách liên kết (Linked List)\n\n_Đọc bằng ngôn ngữ khác:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Español_](README.es-ES.md),\n[_Türkçe_](README.tr-TR.md),\n[_Українська_](README.uk-UA.md)\n\n\nTrong 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\ncác phần tử dữ liệu, trong đó thứ tự tuyến tính không được xác định bởi\nvị trí vật lý của chúng trong bộ nhớ. Thay vào đó, mỗi\nphần tử trỏ đến phần tử tiếp theo. Đây là một cấu trúc dữ liệu\nbao gồm một nhóm các nút cùng đại diện cho\nmột chuỗi. Dưới dạng đơn giản nhất, mỗi nút\nbao gồm dữ liệu và một tham chiếu (nói cách khác,\nmột liên kết) đến nút tiếp theo trong chuỗi. Cấu trúc này\ncho phép việc chèn hoặc loại bỏ các phần tử một cách hiệu quả\ntừ bất kỳ vị trí nào trong chuỗi trong quá trình lặp.\nCác biến thể phức tạp hơn thêm các liên kết bổ sung, cho phép\nviệc chèn hoặc loại bỏ một cách hiệu quả từ bất kỳ phần tử nào\ntrong chuỗi dựa trên tham chiếu. Một nhược điểm của danh sách liên kết\nlà thời gian truy cập tuyến tính (và khó điều chỉnh). Truy cập nhanh hơn,\nnhư truy cập ngẫu nhiên, là không khả thi. Mảng\ncó độ tương phản cache tốt hơn so với danh sách liên kết.\n\n![Linked List](./images/linked-list.jpeg)\n*Được làm từ [okso.app](https://okso.app)*\n\n## Mã giải (Pseudocode) cho Các Hoạt Động Cơ Bản\n  *head = đầu,\n  *tail = đuôi,\n  *next = kế tiếp,\n  *node = nút,\n  *value = giá trị\n\n### Chèn (Insert)\n\n```\nThêmGiáTrị(giá trị) (Add(value))\n  Trước(Pre): giá trị là giá trị muốn thêm vào danh sách\n  Sau(Post): giá trị đã được đặt ở cuối danh sách\n\n n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend ThêmGiáTrị(Add)\n```\n\n```\nChènVàoĐầu(giá trị)\n  Trước(Pre): giá trị là giá trị muốn thêm vào danh sách\n  Sau(Post): giá trị đã được đặt ở đầu danh sách\n\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend ChènVàoĐầu\n```\n\n### Tìm Kiếm (Search)\n```\nChứa(đầu, giá trị)\n  Trước: đầu là nút đầu trong danh sách\n       giá trị là giá trị cần tìm kiếm\n  Sau: mục đó có thể ở trong danh sách liên kết, true; nếu không, là false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### Xóa (Delete)\n```\nXóa(đầu, giá trị)\n  Trước: đầu là nút đầu trong danh sách\n       giá trị là giá trị cần xóa khỏi danh sách\n  Sau: giá trị đã được xóa khỏi danh sách, true; nếu không, là false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n      tail.next = null\n    else\n      n.next ← n.next.next\n    end if\n    return true\n  end if\n  return false\nend Remove\n```\n\n### Duyệt(raverse)\nDuyệt(đầu)\n  Trước: đầu là nút đầu trong danh sách\n  Sau: các mục trong danh sách đã được duyệt\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n\n### Duyệt Ngược (Traverse in Reverse)\nDuyệtNgược(đầu, đuôi)\n  Trước: đầu và đuôi thuộc cùng một danh sách\n  Sau: các mục trong danh sách đã được duyệt theo thứ tự ngược lại\n\n## Độ Phức Tạp\n\n### Độ Phức Tạp Thời Gian (Time Complexity)\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(n)      |\n\n## Độ Phức Tạp Không Gian (Space Complexity)\nO(n)\n\n## Tham Khảo\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/README.zh-CN.md",
    "content": "# 链表\n\n在计算机科学中, 一个 **链表** 是数据元素的线性集合, 元素的线性顺序不是由它们在内存中的物理位置给出的。 相反, 每个元素指向下一个元素。它是由一组节点组成的数据结构,这些节点一起,表示序列。\n\n在最简单的形式下，每个节点由数据和到序列中下一个节点的引用(换句话说，链接)组成。这种结构允许在迭代期间有效地从序列中的任何位置插入或删除元素。\n\n更复杂的变体添加额外的链接，允许有效地插入或删除任意元素引用。链表的一个缺点是访问时间是线性的(而且难以管道化)。\n\n更快的访问，如随机访问，是不可行的。与链表相比，数组具有更好的缓存位置。\n\n![Linked List](./images/linked-list.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 基本操作的伪代码\n\n### 插入\n\n```text\nAdd(value)\n  Pre: value is the value to add to the list\n  Post: value has been placed at the tail of the list\n  n ← node(value)\n  if head = ø\n    head ← n\n    tail ← n\n  else\n    tail.next ← n\n    tail ← n\n  end if\nend Add\n```\n\n```\nPrepend(value)\n Pre: value is the value to add to the list\n Post: value has been placed at the head of the list\n n ← node(value)\n n.next ← head\n head ← n\n if tail = ø\n   tail ← n\n end\nend Prepend\n```\n\n### 搜索\n\n```text\nContains(head, value)\n  Pre: head is the head node in the list\n       value is the value to search for\n  Post: the item is either in the linked list, true; otherwise false\n  n ← head\n  while n != ø and n.value != value\n    n ← n.next\n  end while\n  if n = ø\n    return false\n  end if\n  return true\nend Contains\n```\n\n### 删除\n\n```text\nRemove(head, value)\n  Pre: head is the head node in the list\n       value is the value to remove from the list\n  Post: value is removed from the list, true, otherwise false\n  if head = ø\n    return false\n  end if\n  n ← head\n  if n.value = value\n    if head = tail\n      head ← ø\n      tail ← ø\n    else\n      head ← head.next\n    end if\n    return true\n  end if\n  while n.next != ø and n.next.value != value\n    n ← n.next\n  end while\n  if n.next != ø\n    if n.next = tail\n      tail ← n\n    end if\n    n.next ← n.next.next\n    return true\n  end if\n  return false\nend Remove\n```\n\n### 遍历\n\n```text\nTraverse(head)\n  Pre: head is the head node in the list\n  Post: the items in the list have been traversed\n  n ← head\n  while n != ø\n    yield n.value\n    n ← n.next\n  end while\nend Traverse\n```\n\n### 反向遍历\n\n```text\nReverseTraversal(head, tail)\n  Pre: head and tail belong to the same list\n  Post: the items in the list have been traversed in reverse order\n  if tail != ø\n    curr ← tail\n    while curr != head\n      prev ← head\n      while prev.next != curr\n        prev ← prev.next\n      end while\n      yield curr.value\n      curr ← prev\n    end while\n   yield curr.value\n  end if\nend ReverseTraversal\n```\n\n## 复杂度\n\n### 时间复杂度\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(n)      | O(n)      | O(1)      | O(1)      |\n\n### 空间复杂度\n\nO(n)\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/linked-list/__test__/LinkedList.test.js",
    "content": "import LinkedList from '../LinkedList';\n\ndescribe('LinkedList', () => {\n  it('should create empty linked list', () => {\n    const linkedList = new LinkedList();\n    expect(linkedList.toString()).toBe('');\n  });\n\n  it('should append node to linked list', () => {\n    const linkedList = new LinkedList();\n\n    expect(linkedList.head).toBeNull();\n    expect(linkedList.tail).toBeNull();\n\n    linkedList.append(1);\n    linkedList.append(2);\n\n    expect(linkedList.toString()).toBe('1,2');\n    expect(linkedList.tail.next).toBeNull();\n  });\n\n  it('should prepend node to linked list', () => {\n    const linkedList = new LinkedList();\n\n    linkedList.prepend(2);\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    linkedList.append(1);\n    linkedList.prepend(3);\n\n    expect(linkedList.toString()).toBe('3,2,1');\n  });\n\n  it('should insert node to linked list', () => {\n    const linkedList = new LinkedList();\n\n    linkedList.insert(4, 3);\n    expect(linkedList.head.toString()).toBe('4');\n    expect(linkedList.tail.toString()).toBe('4');\n\n    linkedList.insert(3, 2);\n    linkedList.insert(2, 1);\n    linkedList.insert(1, -7);\n    linkedList.insert(10, 9);\n\n    expect(linkedList.toString()).toBe('1,4,2,3,10');\n  });\n\n  it('should delete node by value from linked list', () => {\n    const linkedList = new LinkedList();\n\n    expect(linkedList.delete(5)).toBeNull();\n\n    linkedList.append(1);\n    linkedList.append(1);\n    linkedList.append(2);\n    linkedList.append(3);\n    linkedList.append(3);\n    linkedList.append(3);\n    linkedList.append(4);\n    linkedList.append(5);\n\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('5');\n\n    const deletedNode = linkedList.delete(3);\n    expect(deletedNode.value).toBe(3);\n    expect(linkedList.toString()).toBe('1,1,2,4,5');\n\n    linkedList.delete(3);\n    expect(linkedList.toString()).toBe('1,1,2,4,5');\n\n    linkedList.delete(1);\n    expect(linkedList.toString()).toBe('2,4,5');\n\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('5');\n\n    linkedList.delete(5);\n    expect(linkedList.toString()).toBe('2,4');\n\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('4');\n\n    linkedList.delete(4);\n    expect(linkedList.toString()).toBe('2');\n\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    linkedList.delete(2);\n    expect(linkedList.toString()).toBe('');\n  });\n\n  it('should delete linked list tail', () => {\n    const linkedList = new LinkedList();\n\n    linkedList.append(1);\n    linkedList.append(2);\n    linkedList.append(3);\n\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('3');\n\n    const deletedNode1 = linkedList.deleteTail();\n\n    expect(deletedNode1.value).toBe(3);\n    expect(linkedList.toString()).toBe('1,2');\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    const deletedNode2 = linkedList.deleteTail();\n\n    expect(deletedNode2.value).toBe(2);\n    expect(linkedList.toString()).toBe('1');\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('1');\n\n    const deletedNode3 = linkedList.deleteTail();\n\n    expect(deletedNode3.value).toBe(1);\n    expect(linkedList.toString()).toBe('');\n    expect(linkedList.head).toBeNull();\n    expect(linkedList.tail).toBeNull();\n  });\n\n  it('should delete linked list head', () => {\n    const linkedList = new LinkedList();\n\n    expect(linkedList.deleteHead()).toBeNull();\n\n    linkedList.append(1);\n    linkedList.append(2);\n\n    expect(linkedList.head.toString()).toBe('1');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    const deletedNode1 = linkedList.deleteHead();\n\n    expect(deletedNode1.value).toBe(1);\n    expect(linkedList.toString()).toBe('2');\n    expect(linkedList.head.toString()).toBe('2');\n    expect(linkedList.tail.toString()).toBe('2');\n\n    const deletedNode2 = linkedList.deleteHead();\n\n    expect(deletedNode2.value).toBe(2);\n    expect(linkedList.toString()).toBe('');\n    expect(linkedList.head).toBeNull();\n    expect(linkedList.tail).toBeNull();\n  });\n\n  it('should be possible to store objects in the list and to print them out', () => {\n    const linkedList = new LinkedList();\n\n    const nodeValue1 = { value: 1, key: 'key1' };\n    const nodeValue2 = { value: 2, key: 'key2' };\n\n    linkedList\n      .append(nodeValue1)\n      .prepend(nodeValue2);\n\n    const nodeStringifier = (value) => `${value.key}:${value.value}`;\n\n    expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1');\n  });\n\n  it('should find node by value', () => {\n    const linkedList = new LinkedList();\n\n    expect(linkedList.find({ value: 5 })).toBeNull();\n\n    linkedList.append(1);\n    expect(linkedList.find({ value: 1 })).toBeDefined();\n\n    linkedList\n      .append(2)\n      .append(3);\n\n    const node = linkedList.find({ value: 2 });\n\n    expect(node.value).toBe(2);\n    expect(linkedList.find({ value: 5 })).toBeNull();\n  });\n\n  it('should find node by callback', () => {\n    const linkedList = new LinkedList();\n\n    linkedList\n      .append({ value: 1, key: 'test1' })\n      .append({ value: 2, key: 'test2' })\n      .append({ value: 3, key: 'test3' });\n\n    const node = linkedList.find({ callback: (value) => value.key === 'test2' });\n\n    expect(node).toBeDefined();\n    expect(node.value.value).toBe(2);\n    expect(node.value.key).toBe('test2');\n    expect(linkedList.find({ callback: (value) => value.key === 'test5' })).toBeNull();\n  });\n\n  it('should create linked list from array', () => {\n    const linkedList = new LinkedList();\n    linkedList.fromArray([1, 1, 2, 3, 3, 3, 4, 5]);\n\n    expect(linkedList.toString()).toBe('1,1,2,3,3,3,4,5');\n  });\n\n  it('should find node by means of custom compare function', () => {\n    const comparatorFunction = (a, b) => {\n      if (a.customValue === b.customValue) {\n        return 0;\n      }\n\n      return a.customValue < b.customValue ? -1 : 1;\n    };\n\n    const linkedList = new LinkedList(comparatorFunction);\n\n    linkedList\n      .append({ value: 1, customValue: 'test1' })\n      .append({ value: 2, customValue: 'test2' })\n      .append({ value: 3, customValue: 'test3' });\n\n    const node = linkedList.find({\n      value: { value: 2, customValue: 'test2' },\n    });\n\n    expect(node).toBeDefined();\n    expect(node.value.value).toBe(2);\n    expect(node.value.customValue).toBe('test2');\n    expect(linkedList.find({ value: { value: 2, customValue: 'test5' } })).toBeNull();\n  });\n\n  it('should find preferring callback over compare function', () => {\n    const greaterThan = (value, compareTo) => (value > compareTo ? 0 : 1);\n\n    const linkedList = new LinkedList(greaterThan);\n    linkedList.fromArray([1, 2, 3, 4, 5]);\n\n    let node = linkedList.find({ value: 3 });\n    expect(node.value).toBe(4);\n\n    node = linkedList.find({ callback: (value) => value < 3 });\n    expect(node.value).toBe(1);\n  });\n\n  it('should convert to array', () => {\n    const linkedList = new LinkedList();\n    linkedList.append(1);\n    linkedList.append(2);\n    linkedList.append(3);\n    expect(linkedList.toArray().join(',')).toBe('1,2,3');\n  });\n\n  it('should reverse linked list', () => {\n    const linkedList = new LinkedList();\n\n    // Add test values to linked list.\n    linkedList\n      .append(1)\n      .append(2)\n      .append(3);\n\n    expect(linkedList.toString()).toBe('1,2,3');\n    expect(linkedList.head.value).toBe(1);\n    expect(linkedList.tail.value).toBe(3);\n\n    // Reverse linked list.\n    linkedList.reverse();\n    expect(linkedList.toString()).toBe('3,2,1');\n    expect(linkedList.head.value).toBe(3);\n    expect(linkedList.tail.value).toBe(1);\n\n    // Reverse linked list back to initial state.\n    linkedList.reverse();\n    expect(linkedList.toString()).toBe('1,2,3');\n    expect(linkedList.head.value).toBe(1);\n    expect(linkedList.tail.value).toBe(3);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/linked-list/__test__/LinkedListNode.test.js",
    "content": "import LinkedListNode from '../LinkedListNode';\n\ndescribe('LinkedListNode', () => {\n  it('should create list node with value', () => {\n    const node = new LinkedListNode(1);\n\n    expect(node.value).toBe(1);\n    expect(node.next).toBeNull();\n  });\n\n  it('should create list node with object as a value', () => {\n    const nodeValue = { value: 1, key: 'test' };\n    const node = new LinkedListNode(nodeValue);\n\n    expect(node.value.value).toBe(1);\n    expect(node.value.key).toBe('test');\n    expect(node.next).toBeNull();\n  });\n\n  it('should link nodes together', () => {\n    const node2 = new LinkedListNode(2);\n    const node1 = new LinkedListNode(1, node2);\n\n    expect(node1.next).toBeDefined();\n    expect(node2.next).toBeNull();\n    expect(node1.value).toBe(1);\n    expect(node1.next.value).toBe(2);\n  });\n\n  it('should convert node to string', () => {\n    const node = new LinkedListNode(1);\n\n    expect(node.toString()).toBe('1');\n\n    node.value = 'string value';\n    expect(node.toString()).toBe('string value');\n  });\n\n  it('should convert node to string with custom stringifier', () => {\n    const nodeValue = { value: 1, key: 'test' };\n    const node = new LinkedListNode(nodeValue);\n    const toStringCallback = (value) => `value: ${value.value}, key: ${value.key}`;\n\n    expect(node.toString(toStringCallback)).toBe('value: 1, key: test');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/lru-cache/LRUCache.js",
    "content": "/* eslint-disable no-param-reassign, max-classes-per-file */\n\n/**\n * Simple implementation of the Doubly-Linked List Node\n * that is used in LRUCache class below.\n */\nclass LinkedListNode {\n  /**\n   * Creates a doubly-linked list node.\n   * @param {string} key\n   * @param {any} val\n   * @param {LinkedListNode} prev\n   * @param {LinkedListNode} next\n   */\n  constructor(key, val, prev = null, next = null) {\n    this.key = key;\n    this.val = val;\n    this.prev = prev;\n    this.next = next;\n  }\n}\n\n/**\n * Implementation of the LRU (Least Recently Used) Cache\n * based on the HashMap and Doubly Linked List data-structures.\n *\n * Current implementation allows to have fast O(1) (in average) read and write operations.\n *\n * At any moment in time the LRU Cache holds not more that \"capacity\" number of items in it.\n */\nclass LRUCache {\n  /**\n   * Creates a cache instance of a specific capacity.\n   * @param {number} capacity\n   */\n  constructor(capacity) {\n    this.capacity = capacity; // How many items to store in cache at max.\n    this.nodesMap = {}; // The quick links to each linked list node in cache.\n    this.size = 0; // The number of items that is currently stored in the cache.\n    this.head = new LinkedListNode(); // The Head (first) linked list node.\n    this.tail = new LinkedListNode(); // The Tail (last) linked list node.\n  }\n\n  /**\n   * Returns the cached value by its key.\n   * Time complexity: O(1) in average.\n   * @param {string} key\n   * @returns {any}\n   */\n  get(key) {\n    if (this.nodesMap[key] === undefined) return undefined;\n    const node = this.nodesMap[key];\n    this.promote(node);\n    return node.val;\n  }\n\n  /**\n   * Sets the value to cache by its key.\n   * Time complexity: O(1) in average.\n   * @param {string} key\n   * @param {any} val\n   */\n  set(key, val) {\n    if (this.nodesMap[key]) {\n      const node = this.nodesMap[key];\n      node.val = val;\n      this.promote(node);\n    } else {\n      const node = new LinkedListNode(key, val);\n      this.append(node);\n    }\n  }\n\n  /**\n   * Promotes the node to the end of the linked list.\n   * It means that the node is most frequently used.\n   * It also reduces the chance for such node to get evicted from cache.\n   * @param {LinkedListNode} node\n   */\n  promote(node) {\n    this.evict(node);\n    this.append(node);\n  }\n\n  /**\n   * Appends a new node to the end of the cache linked list.\n   * @param {LinkedListNode} node\n   */\n  append(node) {\n    this.nodesMap[node.key] = node;\n\n    if (!this.head.next) {\n      // First node to append.\n      this.head.next = node;\n      this.tail.prev = node;\n      node.prev = this.head;\n      node.next = this.tail;\n    } else {\n      // Append to an existing tail.\n      const oldTail = this.tail.prev;\n      oldTail.next = node;\n      node.prev = oldTail;\n      node.next = this.tail;\n      this.tail.prev = node;\n    }\n\n    this.size += 1;\n\n    if (this.size > this.capacity) {\n      this.evict(this.head.next);\n    }\n  }\n\n  /**\n   * Evicts (removes) the node from cache linked list.\n   * @param {LinkedListNode} node\n   */\n  evict(node) {\n    delete this.nodesMap[node.key];\n    this.size -= 1;\n\n    const prevNode = node.prev;\n    const nextNode = node.next;\n\n    // If one and only node.\n    if (prevNode === this.head && nextNode === this.tail) {\n      this.head.next = null;\n      this.tail.prev = null;\n      this.size = 0;\n      return;\n    }\n\n    // If this is a Head node.\n    if (prevNode === this.head) {\n      nextNode.prev = this.head;\n      this.head.next = nextNode;\n      return;\n    }\n\n    // If this is a Tail node.\n    if (nextNode === this.tail) {\n      prevNode.next = this.tail;\n      this.tail.prev = prevNode;\n      return;\n    }\n\n    // If the node is in the middle.\n    prevNode.next = nextNode;\n    nextNode.prev = prevNode;\n  }\n}\n\nexport default LRUCache;\n"
  },
  {
    "path": "src/data-structures/lru-cache/LRUCacheOnMap.js",
    "content": "/* eslint-disable no-restricted-syntax, no-unreachable-loop */\n\n/**\n * Implementation of the LRU (Least Recently Used) Cache\n * based on the (ordered) Map data-structure.\n *\n * Current implementation allows to have fast O(1) (in average) read and write operations.\n *\n * At any moment in time the LRU Cache holds not more that \"capacity\" number of items in it.\n */\nclass LRUCacheOnMap {\n  /**\n   * Creates a cache instance of a specific capacity.\n   * @param {number} capacity\n   */\n  constructor(capacity) {\n    this.capacity = capacity; // How many items to store in cache at max.\n    this.items = new Map(); // The ordered hash map of all cached items.\n  }\n\n  /**\n   * Returns the cached value by its key.\n   * Time complexity: O(1) in average.\n   * @param {string} key\n   * @returns {any}\n   */\n  get(key) {\n    if (!this.items.has(key)) return undefined;\n    const val = this.items.get(key);\n    this.items.delete(key);\n    this.items.set(key, val);\n    return val;\n  }\n\n  /**\n   * Sets the value to cache by its key.\n   * Time complexity: O(1).\n   * @param {string} key\n   * @param {any} val\n   */\n  set(key, val) {\n    this.items.delete(key);\n    this.items.set(key, val);\n    if (this.items.size > this.capacity) {\n      for (const headKey of this.items.keys()) {\n        this.items.delete(headKey);\n        break;\n      }\n    }\n  }\n}\n\nexport default LRUCacheOnMap;\n"
  },
  {
    "path": "src/data-structures/lru-cache/README.ko-KR.md",
    "content": "# LRU 캐시 알고리즘\n\n**LRU 캐시 알고리즘** 은 사용된 순서대로 아이템을 정리함으로써, 오랜 시간 동안 사용되지 않은 아이템을 빠르게 찾아낼 수 있도록 한다.\n\n한방향으로만 옷을 걸 수 있는 옷걸이 행거를 생각해봅시다. 가장 오랫동안 입지 않은 옷을 찾기 위해서는, 행거의 반대쪽 끝을 보면 됩니다.\n\n## 문제 정의\n\nLRUCache 클래스를 구현해봅시다:\n\n- `LRUCache(int capacity)` LRU 캐시를 **양수** 의 `capacity` 로 초기화합니다.\n- `int get(int key)` `key` 가 존재할 경우 `key` 값을 반환하고, 그렇지 않으면 `undefined` 를 반환합니다.\n- `void set(int key, int value)` `key` 가 존재할 경우 `key` 값을 업데이트 하고, 그렇지 않으면 `key-value` 쌍을 캐시에 추가합니다. 만약 이 동작으로 인해 키 개수가 `capacity` 를 넘는 경우, 가장 오래된 키 값을 **제거** 합니다.\n\n`get()` 과 `set()` 함수는 무조건 평균 `O(1)` 의 시간 복잡도 내에 실행되어야 합니다.\n\n## 구현\n\n### 버전 1: 더블 링크드 리스트 + 해시맵\n\n[LRUCache.js](./LRUCache.js) 에서 `LRUCache` 구현체 예시를 확인할 수 있습니다. 예시에서는 (평균적으로) 빠른 `O(1)` 캐시 아이템 접근을 위해 `HashMap` 을 사용했고, (평균적으로) 빠른 `O(1)` 캐시 아이템 수정과 제거를 위해 `DoublyLinkedList` 를 사용했습니다. (허용된 최대의 캐시 용량을 유지하기 위해)\n\n![Linked List](./images/lru-cache.jpg)\n\n_[okso.app](https://okso.app) 으로 만듦_\n\nLRU 캐시가 어떻게 작동하는지 더 많은 예시로 확인하고 싶다면 LRUCache.test.js](./**test**/LRUCache.test.js) 파일을 참고하세요.\n\n### 버전 2: 정렬된 맵\n\n더블 링크드 리스트로 구현한 첫번째 예시는 어떻게 평균 `O(1)` 시간 복잡도가 `set()` 과 `get()` 으로 나올 수 있는지 학습 목적과 이해를 돕기 위해 좋은 예시입니다.\n\n그러나, 더 쉬운 방법은 자바스크립트의 [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) 객체를 사용하는 것입니다. 이 `Map` 객체는 키-값 쌍과 키를 **추가하는 순서 원본** 을 지닙니다. 우리는 이걸 아이템을 제거하거나 다시 추가하면서 맵의 \"가장 마지막\" 동작에서 최근에 사용된 아이템을 유지하기 위해 사용할 수 있습니다. `Map` 의 시작점에 있는 아이템은 캐시 용량이 넘칠 경우 가장 먼저 제거되는 대상입니다. 아이템의 순서는 `map.keys()` 와 같은 `IterableIterator` 을 사용해 확인할 수 있습니다.\n\n해당 구현체는 [LRUCacheOnMap.js](./LRUCacheOnMap.js) 의 `LRUCacheOnMap` 예시에서 확인할 수 있습니다.\n\n이 LRU 캐시 방식이 어떻게 작동하는지 더 많은 테스트 케이스를 확인하고 싶다면 [LRUCacheOnMap.test.js](./__test__/LRUCacheOnMap.test.js) 파일을 참고하세요.\n\n## 복잡도\n\n|                 | 평균   |\n| --------------- | ------ |\n| 공간            | `O(n)` |\n| 아이템 찾기     | `O(1)` |\n| 아이템 설정하기 | `O(1)` |\n\n## 참조\n\n- [LRU Cache on LeetCode](https://leetcode.com/problems/lru-cache/solutions/244744/lru-cache/)\n- [LRU Cache on InterviewCake](https://www.interviewcake.com/concept/java/lru-cache)\n- [LRU Cache on Wiki](https://en.wikipedia.org/wiki/Cache_replacement_policies)\n"
  },
  {
    "path": "src/data-structures/lru-cache/README.md",
    "content": "# Least Recently Used (LRU) Cache\n\n_Read this in other languages:_\n[한국어](README.ko-KR.md),\n\nA **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.\n\nPicture 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.\n\n## The problem statement\n\nImplement the LRUCache class:\n\n- `LRUCache(int capacity)` Initialize the LRU cache with **positive** size `capacity`.\n- `int get(int key)` Return the value of the `key` if the `key` exists, otherwise return `undefined`.\n- `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.\n\nThe functions `get()` and `set()` must each run in `O(1)` average time complexity.\n\n## Implementation\n\n### Version 1: Doubly Linked List + Hash Map\n\nSee 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).\n\n![Linked List](./images/lru-cache.jpg)\n\n_Made with [okso.app](https://okso.app)_\n\nYou may also find more test-case examples of how the LRU Cache works in [LRUCache.test.js](./__test__/LRUCache.test.js) file.\n\n### Version 2: Ordered Map\n\nThe 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()`.\n\nHowever, 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()`.\n\nSee the `LRUCacheOnMap` implementation example in [LRUCacheOnMap.js](./LRUCacheOnMap.js).\n\nYou may also find more test-case examples of how the LRU Cache works in [LRUCacheOnMap.test.js](./__test__/LRUCacheOnMap.test.js) file.\n\n## Complexities\n\n|          | Average |\n| -------- | ------- |\n| Space    | `O(n)`  |\n| Get item | `O(1)`  |\n| Set item | `O(1)`  |\n\n## References\n\n- [LRU Cache on LeetCode](https://leetcode.com/problems/lru-cache/solutions/244744/lru-cache/)\n- [LRU Cache on InterviewCake](https://www.interviewcake.com/concept/java/lru-cache)\n- [LRU Cache on Wiki](https://en.wikipedia.org/wiki/Cache_replacement_policies)\n"
  },
  {
    "path": "src/data-structures/lru-cache/__test__/LRUCache.test.js",
    "content": "import LRUCache from '../LRUCache';\n\ndescribe('LRUCache', () => {\n  it('should set and get values to and from the cache', () => {\n    const cache = new LRUCache(100);\n    expect(cache.get('key-1')).toBeUndefined();\n\n    cache.set('key-1', 15);\n    cache.set('key-2', 16);\n    cache.set('key-3', 17);\n    expect(cache.get('key-1')).toBe(15);\n    expect(cache.get('key-2')).toBe(16);\n    expect(cache.get('key-3')).toBe(17);\n    expect(cache.get('key-3')).toBe(17);\n    expect(cache.get('key-2')).toBe(16);\n    expect(cache.get('key-1')).toBe(15);\n\n    cache.set('key-1', 5);\n    cache.set('key-2', 6);\n    cache.set('key-3', 7);\n    expect(cache.get('key-1')).toBe(5);\n    expect(cache.get('key-2')).toBe(6);\n    expect(cache.get('key-3')).toBe(7);\n  });\n\n  it('should evict least recently used items from cache with cache size of 1', () => {\n    const cache = new LRUCache(1);\n    expect(cache.get('key-1')).toBeUndefined();\n\n    cache.set('key-1', 15);\n    expect(cache.get('key-1')).toBe(15);\n\n    cache.set('key-2', 16);\n    expect(cache.get('key-1')).toBeUndefined();\n    expect(cache.get('key-2')).toBe(16);\n\n    cache.set('key-2', 17);\n    expect(cache.get('key-2')).toBe(17);\n\n    cache.set('key-3', 18);\n    cache.set('key-4', 19);\n    expect(cache.get('key-2')).toBeUndefined();\n    expect(cache.get('key-3')).toBeUndefined();\n    expect(cache.get('key-4')).toBe(19);\n  });\n\n  it('should evict least recently used items from cache with cache size of 2', () => {\n    const cache = new LRUCache(2);\n    expect(cache.get('key-21')).toBeUndefined();\n\n    cache.set('key-21', 15);\n    expect(cache.get('key-21')).toBe(15);\n\n    cache.set('key-22', 16);\n    expect(cache.get('key-21')).toBe(15);\n    expect(cache.get('key-22')).toBe(16);\n\n    cache.set('key-22', 17);\n    expect(cache.get('key-22')).toBe(17);\n\n    cache.set('key-23', 18);\n    expect(cache.size).toBe(2);\n    expect(cache.get('key-21')).toBeUndefined();\n    expect(cache.get('key-22')).toBe(17);\n    expect(cache.get('key-23')).toBe(18);\n\n    cache.set('key-24', 19);\n    expect(cache.size).toBe(2);\n    expect(cache.get('key-21')).toBeUndefined();\n    expect(cache.get('key-22')).toBeUndefined();\n    expect(cache.get('key-23')).toBe(18);\n    expect(cache.get('key-24')).toBe(19);\n  });\n\n  it('should evict least recently used items from cache with cache size of 3', () => {\n    const cache = new LRUCache(3);\n\n    cache.set('key-1', 1);\n    cache.set('key-2', 2);\n    cache.set('key-3', 3);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(3);\n\n    cache.set('key-3', 4);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(4);\n\n    cache.set('key-4', 5);\n    expect(cache.get('key-1')).toBeUndefined();\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(4);\n    expect(cache.get('key-4')).toBe(5);\n  });\n\n  it('should promote the node while calling set() method', () => {\n    const cache = new LRUCache(2);\n\n    cache.set('2', 1);\n    cache.set('1', 1);\n    cache.set('2', 3);\n    cache.set('4', 1);\n    expect(cache.get('1')).toBeUndefined();\n    expect(cache.get('2')).toBe(3);\n  });\n\n  it('should promote the recently accessed item with cache size of 3', () => {\n    const cache = new LRUCache(3);\n\n    cache.set('key-1', 1);\n    cache.set('key-2', 2);\n    cache.set('key-3', 3);\n    expect(cache.get('key-1')).toBe(1);\n\n    cache.set('key-4', 4);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-4')).toBe(4);\n    expect(cache.get('key-2')).toBeUndefined();\n  });\n\n  it('should promote the recently accessed item with cache size of 4', () => {\n    const cache = new LRUCache(4);\n\n    cache.set('key-1', 1);\n    cache.set('key-2', 2);\n    cache.set('key-3', 3);\n    cache.set('key-4', 4);\n    expect(cache.get('key-4')).toBe(4);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-1')).toBe(1);\n\n    cache.set('key-5', 5);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-4')).toBeUndefined();\n    expect(cache.get('key-5')).toBe(5);\n\n    cache.set('key-6', 6);\n    expect(cache.get('key-1')).toBeUndefined();\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-4')).toBeUndefined();\n    expect(cache.get('key-5')).toBe(5);\n    expect(cache.get('key-6')).toBe(6);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/lru-cache/__test__/LRUCacheOnMap.test.js",
    "content": "import LRUCache from '../LRUCacheOnMap';\n\ndescribe('LRUCacheOnMap', () => {\n  it('should set and get values to and from the cache', () => {\n    const cache = new LRUCache(100);\n    expect(cache.get('key-1')).toBeUndefined();\n\n    cache.set('key-1', 15);\n    cache.set('key-2', 16);\n    cache.set('key-3', 17);\n    expect(cache.get('key-1')).toBe(15);\n    expect(cache.get('key-2')).toBe(16);\n    expect(cache.get('key-3')).toBe(17);\n    expect(cache.get('key-3')).toBe(17);\n    expect(cache.get('key-2')).toBe(16);\n    expect(cache.get('key-1')).toBe(15);\n\n    cache.set('key-1', 5);\n    cache.set('key-2', 6);\n    cache.set('key-3', 7);\n    expect(cache.get('key-1')).toBe(5);\n    expect(cache.get('key-2')).toBe(6);\n    expect(cache.get('key-3')).toBe(7);\n  });\n\n  it('should evict least recently used items from cache with cache size of 1', () => {\n    const cache = new LRUCache(1);\n    expect(cache.get('key-1')).toBeUndefined();\n\n    cache.set('key-1', 15);\n    expect(cache.get('key-1')).toBe(15);\n\n    cache.set('key-2', 16);\n    expect(cache.get('key-1')).toBeUndefined();\n    expect(cache.get('key-2')).toBe(16);\n\n    cache.set('key-2', 17);\n    expect(cache.get('key-2')).toBe(17);\n\n    cache.set('key-3', 18);\n    cache.set('key-4', 19);\n    expect(cache.get('key-2')).toBeUndefined();\n    expect(cache.get('key-3')).toBeUndefined();\n    expect(cache.get('key-4')).toBe(19);\n  });\n\n  it('should evict least recently used items from cache with cache size of 2', () => {\n    const cache = new LRUCache(2);\n    expect(cache.get('key-21')).toBeUndefined();\n\n    cache.set('key-21', 15);\n    expect(cache.get('key-21')).toBe(15);\n\n    cache.set('key-22', 16);\n    expect(cache.get('key-21')).toBe(15);\n    expect(cache.get('key-22')).toBe(16);\n\n    cache.set('key-22', 17);\n    expect(cache.get('key-22')).toBe(17);\n\n    cache.set('key-23', 18);\n    expect(cache.get('key-21')).toBeUndefined();\n    expect(cache.get('key-22')).toBe(17);\n    expect(cache.get('key-23')).toBe(18);\n\n    cache.set('key-24', 19);\n    expect(cache.get('key-21')).toBeUndefined();\n    expect(cache.get('key-22')).toBeUndefined();\n    expect(cache.get('key-23')).toBe(18);\n    expect(cache.get('key-24')).toBe(19);\n  });\n\n  it('should evict least recently used items from cache with cache size of 3', () => {\n    const cache = new LRUCache(3);\n\n    cache.set('key-1', 1);\n    cache.set('key-2', 2);\n    cache.set('key-3', 3);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(3);\n\n    cache.set('key-3', 4);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(4);\n\n    cache.set('key-4', 5);\n    expect(cache.get('key-1')).toBeUndefined();\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(4);\n    expect(cache.get('key-4')).toBe(5);\n  });\n\n  it('should promote the node while calling set() method', () => {\n    const cache = new LRUCache(2);\n\n    cache.set('2', 1);\n    cache.set('1', 1);\n    cache.set('2', 3);\n    cache.set('4', 1);\n    expect(cache.get('1')).toBeUndefined();\n    expect(cache.get('2')).toBe(3);\n  });\n\n  it('should promote the recently accessed item with cache size of 3', () => {\n    const cache = new LRUCache(3);\n\n    cache.set('key-1', 1);\n    cache.set('key-2', 2);\n    cache.set('key-3', 3);\n    expect(cache.get('key-1')).toBe(1);\n\n    cache.set('key-4', 4);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-4')).toBe(4);\n    expect(cache.get('key-2')).toBeUndefined();\n  });\n\n  it('should promote the recently accessed item with cache size of 4', () => {\n    const cache = new LRUCache(4);\n\n    cache.set('key-1', 1);\n    cache.set('key-2', 2);\n    cache.set('key-3', 3);\n    cache.set('key-4', 4);\n    expect(cache.get('key-4')).toBe(4);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-1')).toBe(1);\n\n    cache.set('key-5', 5);\n    expect(cache.get('key-1')).toBe(1);\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-4')).toBeUndefined();\n    expect(cache.get('key-5')).toBe(5);\n\n    cache.set('key-6', 6);\n    expect(cache.get('key-1')).toBeUndefined();\n    expect(cache.get('key-2')).toBe(2);\n    expect(cache.get('key-3')).toBe(3);\n    expect(cache.get('key-4')).toBeUndefined();\n    expect(cache.get('key-5')).toBe(5);\n    expect(cache.get('key-6')).toBe(6);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/priority-queue/PriorityQueue.js",
    "content": "import MinHeap from '../heap/MinHeap';\nimport Comparator from '../../utils/comparator/Comparator';\n\n// It is the same as min heap except that when comparing two elements\n// we take into account its priority instead of the element's value.\nexport default class PriorityQueue extends MinHeap {\n  constructor() {\n    // Call MinHip constructor first.\n    super();\n\n    // Setup priorities map.\n    this.priorities = new Map();\n\n    // Use custom comparator for heap elements that will take element priority\n    // instead of element value into account.\n    this.compare = new Comparator(this.comparePriority.bind(this));\n  }\n\n  /**\n   * Add item to the priority queue.\n   * @param {*} item - item we're going to add to the queue.\n   * @param {number} [priority] - items priority.\n   * @return {PriorityQueue}\n   */\n  add(item, priority = 0) {\n    this.priorities.set(item, priority);\n    super.add(item);\n    return this;\n  }\n\n  /**\n   * Remove item from priority queue.\n   * @param {*} item - item we're going to remove.\n   * @param {Comparator} [customFindingComparator] - custom function for finding the item to remove\n   * @return {PriorityQueue}\n   */\n  remove(item, customFindingComparator) {\n    super.remove(item, customFindingComparator);\n    this.priorities.delete(item);\n    return this;\n  }\n\n  /**\n   * Change priority of the item in a queue.\n   * @param {*} item - item we're going to re-prioritize.\n   * @param {number} priority - new item's priority.\n   * @return {PriorityQueue}\n   */\n  changePriority(item, priority) {\n    this.remove(item, new Comparator(this.compareValue));\n    this.add(item, priority);\n    return this;\n  }\n\n  /**\n   * Find item by ite value.\n   * @param {*} item\n   * @return {Number[]}\n   */\n  findByValue(item) {\n    return this.find(item, new Comparator(this.compareValue));\n  }\n\n  /**\n   * Check if item already exists in a queue.\n   * @param {*} item\n   * @return {boolean}\n   */\n  hasValue(item) {\n    return this.findByValue(item).length > 0;\n  }\n\n  /**\n   * Compares priorities of two items.\n   * @param {*} a\n   * @param {*} b\n   * @return {number}\n   */\n  comparePriority(a, b) {\n    if (this.priorities.get(a) === this.priorities.get(b)) {\n      return 0;\n    }\n    return this.priorities.get(a) < this.priorities.get(b) ? -1 : 1;\n  }\n\n  /**\n   * Compares values of two items.\n   * @param {*} a\n   * @param {*} b\n   * @return {number}\n   */\n  compareValue(a, b) {\n    if (a === b) {\n      return 0;\n    }\n    return a < b ? -1 : 1;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.fr-FR.md",
    "content": "# File de priorité\n\nEn informatique, une **file de priorité** est un type\nde données abstrait qui s'apparente à une file d'attente normale\nou une structure de données empilées, mais où chaque élément est\nen plus associé à une \"priorité\".\nDans une file de priorité, un élément avec une priorité élevée\nest servi avant un élément à faible priorité. Si deux éléments ont\nla même priorité, ils sont servis selon leur ordre dans la file\nd'attente.\n\nAlors que les files de priorité sont souvent implémentées avec des tas,\nelles sont conceptuellement distinctes des tas. Une file de priorité\nest un concept abstrait comme \"une liste\" ou \"une carte\"; tout comme\nune liste peut être implémentée avec une liste chaînée ou un tableau,\nune file de priorité peut être implémentée avec un tas ou une variété\nd'autres méthodes telles qu'un tableau non ordonné.\n\n## Références\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/File_de_priorit%C3%A9)\n- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.ja-JP.md",
    "content": "# 優先度付きキュー\n\nコンピュータサイエンスにおいて、**優先度付きキュー**は通常のキューやスタックのデータ構造と似た抽象データ型ですが、各要素に「優先度」が関連づけられています。優先度付きキューでは優先度の高い要素が優先度の低い要素よりも先に処理されます。もし2つの要素が同じ優先度だった場合、それらはキュー内の順序に従って処理されます。\n\n優先度付きキューは多くの場合ヒープによって実装されていますが、概念的にはヒープとは異なります。優先度付きキューは「リスト」や「マップ」のような抽象的な概念です。リストがリンクリストや配列で実装できるのと同様に、優先度付きキューはヒープや未ソート配列のような様々な方法で実装することができます。\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)\n- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.ko-KR.md",
    "content": "# 우선 순위 큐 \n\n컴퓨터 과학에서 **우선 순위 큐**는 일반 큐 또는 스택 데이터 구조와 같은 추상 데이터 유형이지만, 여기서 각 요소에는 \"우선 순위\"가 연결됩니다. \n우선 순위 큐에서는 우선 순위가 높은 요소가 낮은 요소 앞에 제공됩니다. 두 요소가 동일한 우선 순위를 가질 경우 큐의 순서에 따라 제공됩니다.\n\n우선 순위 큐는 종종 힙을 사용하여 구현되지만 개념적으로는 힙과 구별됩니다. 우선 순위 대기열은 \"리스트(list)\" 또는 \"맵(map)\"과 같은 추상적인 개념입니다; \n리스트가 링크드 리스트나 배열로 구현될 수 있는 것처럼 우선 순위 큐는 힙이나 정렬되지 않은 배열과 같은 다양한 다른 방법으로 구현될 수 있습니다.\n\n## 참조\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)\n- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.md",
    "content": "# Priority Queue\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Українська_](README.uk-UA.md)\n\nIn computer science, a **priority queue** is an abstract data type\nwhich is like a regular queue or stack data structure, but where\nadditionally each element has a \"priority\" associated with it.\nIn a priority queue, an element with high priority is served before\nan element with low priority. If two elements have the same\npriority, they are served according to their order in the queue.\n\nWhile priority queues are often implemented with heaps, they are\nconceptually distinct from heaps. A priority queue is an abstract\nconcept like \"a list\" or \"a map\"; just as a list can be implemented\nwith a linked list or an array, a priority queue can be implemented\nwith a heap or a variety of other methods such as an unordered\narray.\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)\n- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.pt-BR.md",
    "content": "# Fila de Prioridade (Priority Queue)\n\nNa ciência da computação, uma **fila de prioridade** é um tipo de estrutura de\ndados abastrata que é como uma fila regular (regular queue) ou estrutura de\ndados de pilha (stack), mas adicionalmente cada elemento possui uma\n\"prioridade\" associada.\n\nEm uma fila de prioridade, um elemento com uma prioridade alta é servido\nantes de um elemento com baixa prioridade. Caso dois elementos posusam a\nmesma prioridade, eles serão servidos de acordo com sua ordem na fila.\n\nEnquanto as filas de prioridade são frequentemente implementadas com\npilhas (stacks), elas são conceitualmente distintas das pilhas (stacks).\nA fila de prioridade é um conceito abstrato como uma \"lista\" (list) ou\num \"mapa\" (map); assim como uma lista pode ser implementada com uma\nlista encadeada (liked list) ou um array, a fila de prioridade pode ser\nimplementada com uma pilha (stack) ou com uma variedade de outros métodos,\ncomo um array não ordenado (unordered array).\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)\n- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.ru-RU.md",
    "content": "# Очередь с приоритетом\n\nОчередь с приоритетом (англ. priority queue) — абстрактный тип данных в информатике,\nдля каждого элемента которого можно вычислить его приоритет.\n\nВ очереди с приоритетами элемент с высоким приоритетом обслуживается раньше\nэлемента с низким приоритетом. Если два элемента имеют одинаковый приоритет, они\nобслуживаются в соответствии с их порядком в очереди.\n\nОчередь с приоритетом поддерживает две обязательные операции — добавить элемент и\nизвлечь максимум(минимум).\n\nХотя приоритетные очереди часто реализуются в виде куч(heaps), они\nконцептуально отличаются от куч. Очередь приоритетов является абстрактной\nконцепцией вроде «списка» или «карты»; так же, как список может быть реализован\nв виде связного списка или массива, так и очередь с приоритетом может быть реализована\nв виде кучи или множеством других методов, например в виде неупорядоченного массива.\n\n## Ссылки\n\n- [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))\n- [YouTube](https://www.youtube.com/watch?v=y_2toG5-j_M)\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.uk-UA.md",
    "content": "# Черга з пріоритетом\n\nЧерга з пріоритетом (англ. priority queue) - абстрактний тип даних в інформатиці,\nдля кожного елемента якого можна визначити його пріоритет.\n\nУ черзі з пріоритетами елемент із високим пріоритетом обслуговується раніше\nелемент з низьким пріоритетом. Якщо два елементи мають однаковий пріоритет, вони\nобслуговуються відповідно до їх порядку в черзі.\n\nЧерга з пріоритетом підтримує дві обов'язкові операції – додати елемент та\nвитягти максимум (мінімум).\n\nХоча пріоритетні черги часто реалізуються у вигляді куп (heaps), вони\nконцептуально відрізняються від куп. Черга пріоритетів є абстрактною\nконцепцією на кшталт «списку» чи «карти»; так само, як список може бути реалізований\nу вигляді зв'язкового списку або масиву, так і черга з пріоритетом може бути реалізована\nу вигляді купи або безліччю інших методів, наприклад, у вигляді невпорядкованого масиву.\n\n## Посилання\n\n- [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)\n"
  },
  {
    "path": "src/data-structures/priority-queue/README.zh-CN.md",
    "content": "# 优先队列\n\n在计算机科学中,  **优先级队列(priority queue)** 是一种抽象数据类型, 它类似于常规的队列或栈, 但每个元素都有与之关联的“优先级”。\n\n在优先队列中, 低优先级的元素之前前面应该是高优先级的元素。 如果两个元素具有相同的优先级, 则根据它们在队列中的顺序是它们的出现顺序即可。\n\n优先队列虽通常用堆来实现,但它在概念上与堆不同。优先队列是一个抽象概念，就像“列表”或“图”这样的抽象概念一样; \n\n正如列表可以用链表或数组实现一样，优先队列可以用堆或各种其他方法实现,例如无序数组。\n\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)\n- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)\n"
  },
  {
    "path": "src/data-structures/priority-queue/__test__/PriorityQueue.test.js",
    "content": "import PriorityQueue from '../PriorityQueue';\n\ndescribe('PriorityQueue', () => {\n  it('should create default priority queue', () => {\n    const priorityQueue = new PriorityQueue();\n\n    expect(priorityQueue).toBeDefined();\n  });\n\n  it('should insert items to the queue and respect priorities', () => {\n    const priorityQueue = new PriorityQueue();\n\n    priorityQueue.add(10, 1);\n    expect(priorityQueue.peek()).toBe(10);\n\n    priorityQueue.add(5, 2);\n    expect(priorityQueue.peek()).toBe(10);\n\n    priorityQueue.add(100, 0);\n    expect(priorityQueue.peek()).toBe(100);\n  });\n\n  it('should be possible to use objects in priority queue', () => {\n    const priorityQueue = new PriorityQueue();\n\n    const user1 = { name: 'Mike' };\n    const user2 = { name: 'Bill' };\n    const user3 = { name: 'Jane' };\n\n    priorityQueue.add(user1, 1);\n    expect(priorityQueue.peek()).toBe(user1);\n\n    priorityQueue.add(user2, 2);\n    expect(priorityQueue.peek()).toBe(user1);\n\n    priorityQueue.add(user3, 0);\n    expect(priorityQueue.peek()).toBe(user3);\n  });\n\n  it('should poll from queue with respect to priorities', () => {\n    const priorityQueue = new PriorityQueue();\n\n    priorityQueue.add(10, 1);\n    priorityQueue.add(5, 2);\n    priorityQueue.add(100, 0);\n    priorityQueue.add(200, 0);\n\n    expect(priorityQueue.poll()).toBe(100);\n    expect(priorityQueue.poll()).toBe(200);\n    expect(priorityQueue.poll()).toBe(10);\n    expect(priorityQueue.poll()).toBe(5);\n  });\n\n  it('should be possible to change priority of head node', () => {\n    const priorityQueue = new PriorityQueue();\n\n    priorityQueue.add(10, 1);\n    priorityQueue.add(5, 2);\n    priorityQueue.add(100, 0);\n    priorityQueue.add(200, 0);\n\n    expect(priorityQueue.peek()).toBe(100);\n\n    priorityQueue.changePriority(100, 10);\n    priorityQueue.changePriority(10, 20);\n\n    expect(priorityQueue.poll()).toBe(200);\n    expect(priorityQueue.poll()).toBe(5);\n    expect(priorityQueue.poll()).toBe(100);\n    expect(priorityQueue.poll()).toBe(10);\n  });\n\n  it('should be possible to change priority of internal nodes', () => {\n    const priorityQueue = new PriorityQueue();\n\n    priorityQueue.add(10, 1);\n    priorityQueue.add(5, 2);\n    priorityQueue.add(100, 0);\n    priorityQueue.add(200, 0);\n\n    expect(priorityQueue.peek()).toBe(100);\n\n    priorityQueue.changePriority(200, 10);\n    priorityQueue.changePriority(10, 20);\n\n    expect(priorityQueue.poll()).toBe(100);\n    expect(priorityQueue.poll()).toBe(5);\n    expect(priorityQueue.poll()).toBe(200);\n    expect(priorityQueue.poll()).toBe(10);\n  });\n\n  it('should be possible to change priority along with node addition', () => {\n    const priorityQueue = new PriorityQueue();\n\n    priorityQueue.add(10, 1);\n    priorityQueue.add(5, 2);\n    priorityQueue.add(100, 0);\n    priorityQueue.add(200, 0);\n\n    priorityQueue.changePriority(200, 10);\n    priorityQueue.changePriority(10, 20);\n\n    priorityQueue.add(15, 15);\n\n    expect(priorityQueue.poll()).toBe(100);\n    expect(priorityQueue.poll()).toBe(5);\n    expect(priorityQueue.poll()).toBe(200);\n    expect(priorityQueue.poll()).toBe(15);\n    expect(priorityQueue.poll()).toBe(10);\n  });\n\n  it('should be possible to search in priority queue by value', () => {\n    const priorityQueue = new PriorityQueue();\n\n    priorityQueue.add(10, 1);\n    priorityQueue.add(5, 2);\n    priorityQueue.add(100, 0);\n    priorityQueue.add(200, 0);\n    priorityQueue.add(15, 15);\n\n    expect(priorityQueue.hasValue(70)).toBe(false);\n    expect(priorityQueue.hasValue(15)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/queue/Queue.js",
    "content": "import LinkedList from '../linked-list/LinkedList';\n\nexport default class Queue {\n  constructor() {\n    // We're going to implement Queue based on LinkedList since the two\n    // structures are quite similar. Namely, they both operate mostly on\n    // the elements at the beginning and the end. Compare enqueue/dequeue\n    // operations of Queue with append/deleteHead operations of LinkedList.\n    this.linkedList = new LinkedList();\n  }\n\n  /**\n   * @return {boolean}\n   */\n  isEmpty() {\n    return !this.linkedList.head;\n  }\n\n  /**\n   * Read the element at the front of the queue without removing it.\n   * @return {*}\n   */\n  peek() {\n    if (this.isEmpty()) {\n      return null;\n    }\n\n    return this.linkedList.head.value;\n  }\n\n  /**\n   * Add a new element to the end of the queue (the tail of the linked list).\n   * This element will be processed after all elements ahead of it.\n   * @param {*} value\n   */\n  enqueue(value) {\n    this.linkedList.append(value);\n  }\n\n  /**\n   * Remove the element at the front of the queue (the head of the linked list).\n   * If the queue is empty, return null.\n   * @return {*}\n   */\n  dequeue() {\n    const removedHead = this.linkedList.deleteHead();\n    return removedHead ? removedHead.value : null;\n  }\n\n  /**\n   * @param [callback]\n   * @return {string}\n   */\n  toString(callback) {\n    // Return string representation of the queue's linked list.\n    return this.linkedList.toString(callback);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/queue/README.fr-FR.md",
    "content": "# File\n\nEn informatique, une **file**, aussi appelée file d'attente, est\nsorte particulière de structure de données abstraite dans lequel\nles entités de la collection sont conservées dans l'ordre et les\nopérations principales sur la collection sont le résultat de l'ajout\nd'entités à la position terminale arrière, connue sous le nom de mise\nen file d'attente (\"enqueue\"), et de la suppression des entités de la\nposition terminale avant, appelée retrait de la file d'attente (\"dequeu\").\n\nCela fait de la file d'attente une structure de données PEPS (premier entré,\npremier sorti), en anglais FIFO (first in, first out). Dans une structure de données\nPEPS, le premier élément ajouté à la file d'attente sera le premier à être\nsupprimé. Cela équivaut à l'exigence qu'une fois qu'un nouvel élément est\najouté, tous les éléments qui ont été ajoutés auparavant doivent être supprimés\navant que le nouvel élément ne puisse être supprimé. Souvent, une opération d'aperçu\nou de front est également intégrée, renvoyant la valeur de l'élément avant\nsans le retirer de la file d'attente. Une file d'attente est un exemple de\nstructure de données linéaire, ou, plus abstraitement, une collection séquentielle.\n\nReprésentation d'une file PEPS (premier entré, premier sorti)\n\n![Queue](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Références\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/File_(structure_de_donn%C3%A9es))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/queue/README.ja-JP.md",
    "content": "# キュー\n\nコンピュータサイエンスにおいて、**キュー**は特定の種類の抽象データ型またはコレクションです。コレクションの中のエンティティは順番に並べられており、コレクションに対する基本的な（または唯一の)操作は末尾にエンティティを追加するエンキューと、先頭からエンティティを削除するデキューがあります。これにより、キューは先入れ先出し(FIFO)のデータ構造となります。FIFOのデータ構造では、キューに追加された最初の要素が最初に削除されます。これは、新しい要素が追加されたら、その要素を削除するにはそれまでに追加された全ての要素が削除されなければならないという要件と同じです。多くの場合、ピークのような先頭の要素を検査する操作も備えていて、これはデキューせずに先頭の要素の値を返します。キューは線形のデータ構造や、より抽象的なシーケンシャルなコレクションの一例です。\n\nFIFO(先入れ先出し)のキュー\n\n![Queue](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/queue/README.ko-KR.md",
    "content": "# Queue\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md)\n\n컴퓨터 공학에서 **큐**는 일종의 추상 데이터 타입이자 컬렉션입니다. 큐 내부의 엔터티들은 순서를 유지하며 컬렉션의 가장 뒷 부분에 엔터티를 추가하는 인큐(enqueue), 컬렉션의 가장 앞에 위치한 엔터티를 제거하는 디큐(dequeue) 작업을 수행합니다. 이것은 큐를 선입선출 자료 구조로 만듭니다. 선입선출 자료 구조에서는, 추가된 첫 번째 요소가 가장 먼저 제거되는 요소가 됩니다. 이는 새로운 요소가 추가되면 이전에 추가되었던 모든 요소들을 제거해야 새로운 요소를 제거할 수 있다는것과 같은 의미입니다. 또한 큐의 가장 앞에 위치한 요소를 반환하기 위한 작업이 입력되면 디큐 작업 없이 해당 요소를 반환합니다.\n\n큐는 선형 자료 구조의 예시이며, 더 추상적으로는 순차적인 컬렉션입니다.\n\n선입선출 자료 구조인 큐를 나타내면 다음과 같습니다.\n\n![Queue](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 참고\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/queue/README.md",
    "content": "# Queue\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Українська_](README.uk-UA.md)\n\nIn computer science, a **queue** is a particular kind of abstract data\ntype or collection in which the entities in the collection are\nkept in order and the principle (or only) operations on the\ncollection are the addition of entities to the rear terminal\nposition, known as enqueue, and removal of entities from the\nfront terminal position, known as dequeue. This makes the queue\na First-In-First-Out (FIFO) data structure. In a FIFO data\nstructure, the first element added to the queue will be the\nfirst one to be removed. This is equivalent to the requirement\nthat once a new element is added, all elements that were added\nbefore have to be removed before the new element can be removed.\nOften a peek or front operation is also entered, returning the\nvalue of the front element without dequeuing it. A queue is an\nexample of a linear data structure, or more abstractly a\nsequential collection.\n\nRepresentation of a FIFO (first in, first out) queue\n\n![Queue](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/queue/README.pt-BR.md",
    "content": "# Fila (Queue)\n\nNa ciência da computação, uma **fila** é um tipo particular de abstração\nde tipo de dado ou coleção em que as entidades na coleção são mantidas em\nordem e a causa primária (ou única) de operações na coleção são a\nadição de entidades à posição final da coleção, conhecido como enfileiramento\n(enqueue) e a remoção de entidades do posição inicial, conhecida como desenfileirar\n(dequeue).Isto torna a fila uma estrutura de dados tipo First-In-First-Out (FIFO).\n\nEm uma estrutura de dados FIFO, o primeiro elemento adicionado a fila\nserá o primeiro a ser removido. Isso é equivalente ao requisito em que uma vez\nque um novo elemento é adicionado, todos os elementos que foram adicionados\nanteriormente devem ser removidos antes que o novo elemento possa ser removido.\n\nMuitas vezes uma espiada (peek) ou uma operação de frente é iniciada,\nretornando o valor do elemento da frente, sem desenfileira-lo. Uma lista é\num exemplo de uma estrutura de dados linear, ou mais abstratamente uma\ncoleção seqüencial.\n\n\nRepresentação de uma file FIFO (first in, first out)\n\n![Queue](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/queue/README.ru-RU.md",
    "content": "# Очередь\n\nОчередь (англ. queue) - структура данных в информатике, в которой элементы\nхранятся в порядке их добавления. Добавление новых элементов(enqueue)\nосуществляется в конец списка. А удаление элементов (dequeue)\nосуществляется с начала. Таким образом очередь реализует принцип\n\"первым вошёл - первым вышел\" (FIFO). Часто реализуется операция чтения\nголовного элемента (peek), которая возвращает первый в очереди элемент,\nпри этом не удаляя его. Очередь является примером линейной структуры\nданных или последовательной коллекции.\n\nИллюстрация работы с очередью.\n\n![Очередь](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [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))\n- [YouTube](https://www.youtube.com/watch?v=GRsVMTlBIoE)\n"
  },
  {
    "path": "src/data-structures/queue/README.uk-UA.md",
    "content": "# Черга\n\nЧерга (англ. queue) – структура даних в інформатиці, в якій елементи\nзберігаються у порядку їх додавання. Додавання нових елементів(enqueue)\nздійснюється на кінець списку. А видалення елементів (dequeue)\nздійснюється із початку. Таким чином черга реалізує принцип\n\"першим увійшов – першим вийшов\" (FIFO). Часто реалізується операція читання\nголовного елемента (peek), яка повертає перший у черзі елемент,\nпри цьому не видаляючи його. Черга є прикладом лінійної структури\nданих чи послідовної колекції.\n\nІлюстрація роботи з чергою.\n\n![Черга](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Список літератури\n\n- [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))\n- [YouTube](https://www.youtube.com/watch?v=ll4QLNSPn60)\n"
  },
  {
    "path": "src/data-structures/queue/README.vi-VN.md",
    "content": "# Hàng đợi (Queue)\n\n_Đọc bằng ngôn ngữ khác:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Українська_](README.uk-UA.md)\n\nTrong 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ự.\n\nHàng đợi FIFO (First-In-First-Out) có thể được biểu diễn như sau:\n\n![Queue](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Tham Khảo\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/queue/README.zh-CN.md",
    "content": "# 队列\n\n在计算机科学中, 一个 **队列(queue)** 是一种特殊类型的抽象数据类型或集合。集合中的实体按顺序保存。\n\n队列基本操作有两种：入队和出队。从队列的后端位置添加实体，称为入队；从队列的前端位置移除实体，称为出队。\n\n\n队列中元素先进先出 FIFO (first in, first out)的示意\n\n![Queue](./images/queue.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/queue/__test__/Queue.test.js",
    "content": "import Queue from '../Queue';\n\ndescribe('Queue', () => {\n  it('should create empty queue', () => {\n    const queue = new Queue();\n    expect(queue).not.toBeNull();\n    expect(queue.linkedList).not.toBeNull();\n  });\n\n  it('should enqueue data to queue', () => {\n    const queue = new Queue();\n\n    queue.enqueue(1);\n    queue.enqueue(2);\n\n    expect(queue.toString()).toBe('1,2');\n  });\n\n  it('should be possible to enqueue/dequeue objects', () => {\n    const queue = new Queue();\n\n    queue.enqueue({ value: 'test1', key: 'key1' });\n    queue.enqueue({ value: 'test2', key: 'key2' });\n\n    const stringifier = (value) => `${value.key}:${value.value}`;\n\n    expect(queue.toString(stringifier)).toBe('key1:test1,key2:test2');\n    expect(queue.dequeue().value).toBe('test1');\n    expect(queue.dequeue().value).toBe('test2');\n  });\n\n  it('should peek data from queue', () => {\n    const queue = new Queue();\n\n    expect(queue.peek()).toBeNull();\n\n    queue.enqueue(1);\n    queue.enqueue(2);\n\n    expect(queue.peek()).toBe(1);\n    expect(queue.peek()).toBe(1);\n  });\n\n  it('should check if queue is empty', () => {\n    const queue = new Queue();\n\n    expect(queue.isEmpty()).toBe(true);\n\n    queue.enqueue(1);\n\n    expect(queue.isEmpty()).toBe(false);\n  });\n\n  it('should dequeue from queue in FIFO order', () => {\n    const queue = new Queue();\n\n    queue.enqueue(1);\n    queue.enqueue(2);\n\n    expect(queue.dequeue()).toBe(1);\n    expect(queue.dequeue()).toBe(2);\n    expect(queue.dequeue()).toBeNull();\n    expect(queue.isEmpty()).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/stack/README.fr-FR.md",
    "content": "# Pile\n\nEn informatique, une **pile** est un type de données abstrait\nqui sert de collection d'éléments, avec deux opérations principales:\n\n* **empiler** (en anglais *push*), qui ajoute un élément à la collection, et\n* **dépiler** (en anglais *pop*), qui supprime l'élément le plus récemment\najouté qui n'a pas encore été supprimé.\n\nL'ordre dans lequel les éléments sortent d'une pile donne\nlieu à son nom alternatif, LIFO (\"last in, first out\",\nlittéralement \"dernier arrivé, premier sorti\"). En outre,\nune opération d'aperçu peut donner accès au sommet sans\nmodifier la pile. Le nom \"pile\" pour ce type de structure\nvient de l'analogie avec un ensemble d'éléments physiques empilés\nles uns sur les autres, ce qui permet de retirer facilement un\nélément du haut de la pile, tout comme accéder à un élément plus\nprofond dans le la pile peut nécessiter de retirer plusieurs\nautres articles en premier.\n\nReprésentation simple de l'éxecution d'une pile avec des opérations empiler (push) et dépiler (pop).\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Références\n\n- [Wikipedia](https://fr.wikipedia.org/wiki/Pile_(informatique))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/stack/README.ja-JP.md",
    "content": "# スタック\n\nコンピュータサイエンスにおいて、**スタック**は抽象データ型で、2つの主要な操作ができる要素のコレクションです。\n\n* **プッシュ**はコレクションに要素を追加します。\n* **ポップ**は最近追加された要素でまだ削除されていないものを削除します。\n\n要素がスタックから外れる順番から、LIFO(後入れ先出し)とも呼ばれます。スタックに変更を加えることなく、先頭の要素を検査するピーク操作を備えることもあります。「スタック」という名前は、物理的な物を上に積み重ねていく様子との類似性に由来しています。一番上の物を取ることは簡単ですが、スタックの下の方にあるものを取るときは先に上にある複数の物を取り除く必要があります。\n\nプッシュとポップの例\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/stack/README.ko-KR.md",
    "content": "# 스택\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md)\n\n컴퓨터 과학에서, **스택**은 아래의 두가지 연산을 가진 요소들의 집합인 추상 자료형입니다.\n\n* **push**는 집합에 요소를 추가하는 것이며,\n* **pop**은 아직 제거되지 않은 가장 최근에 추가된 요소를 제거하는 연산입니다.\n\n요소가 스택에서 나오는 과정은 LIFO (last in, first out)라는 이름으로 확인할 수 있습니다. 추가적으로, peek 연산은 스택을 수정하지 않고 최상단의 요소에 접근할 수 있게 해줍니다. 이런 자료구조의 \"스택\"이라는 이름은 실제 물건들이 다른 물건들의 위에 쌓이게 되는 것에서 유추되었습니다. 스택의 최상단의 물건은 빼내기 쉽지만 깊이 있는 물건을 빼내려면 다른 물건들을 먼저 빼내야 하는게 필요합니다.\n\n다음은 push와 pop 연산을 실행하는 간단한 스택의 실행입니다.\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 참조\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/stack/README.md",
    "content": "# Stack\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Français_](README.fr-FR.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Українська_](README.uk-UA.md)\n\nIn computer science, a **stack** is an abstract data type that serves\nas a collection of elements, with two principal operations:\n\n* **push**, which adds an element to the collection, and\n* **pop**, which removes the most recently added element that was not yet removed.\n\nThe order in which elements come off a stack gives rise to its\nalternative name, LIFO (last in, first out). Additionally, a\npeek operation may give access to the top without modifying\nthe stack. The name \"stack\" for this type of structure comes\nfrom the analogy to a set of physical items stacked on top of\neach other, which makes it easy to take an item off the top\nof the stack, while getting to an item deeper in the stack\nmay require taking off multiple other items first.\n\nSimple representation of a stack runtime with push and pop operations.\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/stack/README.pt-BR.md",
    "content": "# Pilha (Stack)\n\nNa ciência da computação, uma **pilha** é uma estrutura de dados abstrata\nque serve como uma coleção de elementos com duas operações principais:\n\n* **push**, pela qual adiciona um elemento à coleção, e\n* **pop**, pela qual remove o último elemento adicionado.\n\nA ordem em que os elementos saem de um _stack_ dá origem ao seu\nnome alternativo, LIFO (last in, first out). Adicionalmente, uma operação\nde espiada (peek) pode dar acesso ao topo sem modificar o _stack_.\nO nome \"stack\" para este tipo de estrutura vem da analogia de\num conjunto de itens físicos empilhados uns sobre os outros,\no que facilita retirar um item do topo da pilha, enquanto para chegar a\num item mais profundo na pilha pode exigir a retirada de\nvários outros itens primeiro.\n\nRepresentação simples de um tempo de execução de pilha com operações\n_push_ e _pop_.\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/stack/README.ru-RU.md",
    "content": "# Стек\n\nСтек (англ. stack — стопка) — абстрактный тип данных, представляющий собой\nсписок элементов, организованных по принципу LIFO (последним пришёл — первым вышел).\n\nСтек имеет две ключевые операции:\n* **добавление (push)** элемента в конец стека, и\n* **удаление (pop)**, последнего добавленного элемента.\n\nДополнительная операция чтения головного элемента (peek) даёт доступ\nк последнему элементу стека без изменения самого стека.\n\nЧаще всего принцип работы стека сравнивают со стопкой тарелок: чтобы взять вторую\nсверху, нужно снять верхнюю.\n\nИллюстрация работы со стеком.\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Ссылки\n\n- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA)\n- [YouTube](https://www.youtube.com/watch?v=tH8qi7lej5U)\n"
  },
  {
    "path": "src/data-structures/stack/README.uk-UA.md",
    "content": "# Стек\n\nСтек (англ. stack - стопка) - абстрактний тип даних, що представляє собою\nсписок елементів, організованих за принципом LIFO (останнім прийшов – першим вийшов).\n\nСтек має дві ключові операції:\n* **додавання (push)** елемента в кінець стеку, та\n* **видалення (pop)**, останнього доданого елемента.\n\nДодаткова операція для читання головного елемента (peek) дає доступ\nдо останнього елементу стека без зміни самого стека.\n\nНайчастіше принцип роботи стека порівнюють із стопкою тарілок: щоб узяти другу\nзверху потрібно спочатку зняти верхню.\n\nІлюстрація роботи зі стеком.\n\n![Стек](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Посилання\n\n- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA)\n- [YouTube](https://www.youtube.com/watch?v=4jh1e1YCbYc)\n"
  },
  {
    "path": "src/data-structures/stack/README.vi-VN.md",
    "content": "# Ngăn xếp (stack)\n\n_Đọc bằng ngôn ngữ khác:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_日本語_](README.ja-JP.md),\n[_Português_](README.pt-BR.md),\n[_한국어_](README.ko-KR.md),\n[_Español_](README.es-ES.md),\n[_Українська_](README.uk-UA.md)\n\nTrong 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:\n\nđẩy (push), thêm một phần tử vào bộ sưu tập, và\nlấy (pop), loại bỏ phần tử được thêm gần nhất mà chưa được loại bỏ.\nThứ 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 đó.\n\nBiể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.\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Tham Khảo\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/stack/README.zh-CN.md",
    "content": "# 栈\n\n在计算机科学中, 一个 **栈(stack)** 是一种抽象数据类型,用作表示元素的集合,具有两种主要操作:\n\n* **push**, 添加元素到栈的顶端(末尾);\n* **pop**, 移除栈最顶端(末尾)的元素.\n\n以上两种操作可以简单概括为“后进先出(LIFO = last in, first out)”。\n\n此外,应有一个 `peek` 操作用于访问栈当前顶端(末尾)的元素。\n\n\"栈\"这个名称,可类比于一组物体的堆叠(一摞书,一摞盘子之类的)。\n\n栈的 push 和 pop 操作的示意\n\n![Stack](./images/stack.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))\n- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)\n"
  },
  {
    "path": "src/data-structures/stack/Stack.js",
    "content": "import LinkedList from '../linked-list/LinkedList';\n\nexport default class Stack {\n  constructor() {\n    // We're going to implement Stack based on LinkedList since these\n    // structures are quite similar. Compare push/pop operations of the Stack\n    // with prepend/deleteHead operations of LinkedList.\n    this.linkedList = new LinkedList();\n  }\n\n  /**\n   * @return {boolean}\n   */\n  isEmpty() {\n    // The stack is empty if its linked list doesn't have a head.\n    return !this.linkedList.head;\n  }\n\n  /**\n   * @return {*}\n   */\n  peek() {\n    if (this.isEmpty()) {\n      // If the linked list is empty then there is nothing to peek from.\n      return null;\n    }\n\n    // Just read the value from the start of linked list without deleting it.\n    return this.linkedList.head.value;\n  }\n\n  /**\n   * @param {*} value\n   */\n  push(value) {\n    // Pushing means to lay the value on top of the stack. Therefore let's just add\n    // the new value at the start of the linked list.\n    this.linkedList.prepend(value);\n  }\n\n  /**\n   * @return {*}\n   */\n  pop() {\n    // Let's try to delete the first node (the head) from the linked list.\n    // If there is no head (the linked list is empty) just return null.\n    const removedHead = this.linkedList.deleteHead();\n    return removedHead ? removedHead.value : null;\n  }\n\n  /**\n   * @return {*[]}\n   */\n  toArray() {\n    return this.linkedList\n      .toArray()\n      .map((linkedListNode) => linkedListNode.value);\n  }\n\n  /**\n   * @param {function} [callback]\n   * @return {string}\n   */\n  toString(callback) {\n    return this.linkedList.toString(callback);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/stack/__test__/Stack.test.js",
    "content": "import Stack from '../Stack';\n\ndescribe('Stack', () => {\n  it('should create empty stack', () => {\n    const stack = new Stack();\n    expect(stack).not.toBeNull();\n    expect(stack.linkedList).not.toBeNull();\n  });\n\n  it('should stack data to stack', () => {\n    const stack = new Stack();\n\n    stack.push(1);\n    stack.push(2);\n\n    expect(stack.toString()).toBe('2,1');\n  });\n\n  it('should peek data from stack', () => {\n    const stack = new Stack();\n\n    expect(stack.peek()).toBeNull();\n\n    stack.push(1);\n    stack.push(2);\n\n    expect(stack.peek()).toBe(2);\n    expect(stack.peek()).toBe(2);\n  });\n\n  it('should check if stack is empty', () => {\n    const stack = new Stack();\n\n    expect(stack.isEmpty()).toBe(true);\n\n    stack.push(1);\n\n    expect(stack.isEmpty()).toBe(false);\n  });\n\n  it('should pop data from stack', () => {\n    const stack = new Stack();\n\n    stack.push(1);\n    stack.push(2);\n\n    expect(stack.pop()).toBe(2);\n    expect(stack.pop()).toBe(1);\n    expect(stack.pop()).toBeNull();\n    expect(stack.isEmpty()).toBe(true);\n  });\n\n  it('should be possible to push/pop objects', () => {\n    const stack = new Stack();\n\n    stack.push({ value: 'test1', key: 'key1' });\n    stack.push({ value: 'test2', key: 'key2' });\n\n    const stringifier = (value) => `${value.key}:${value.value}`;\n\n    expect(stack.toString(stringifier)).toBe('key2:test2,key1:test1');\n    expect(stack.pop().value).toBe('test2');\n    expect(stack.pop().value).toBe('test1');\n  });\n\n  it('should be possible to convert stack to array', () => {\n    const stack = new Stack();\n\n    expect(stack.peek()).toBeNull();\n\n    stack.push(1);\n    stack.push(2);\n    stack.push(3);\n\n    expect(stack.toArray()).toEqual([3, 2, 1]);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/tree/BinaryTreeNode.js",
    "content": "import Comparator from '../../utils/comparator/Comparator';\nimport HashTable from '../hash-table/HashTable';\n\nexport default class BinaryTreeNode {\n  /**\n   * @param {*} [value] - node value.\n   */\n  constructor(value = null) {\n    this.left = null;\n    this.right = null;\n    this.parent = null;\n    this.value = value;\n\n    // Any node related meta information may be stored here.\n    this.meta = new HashTable();\n\n    // This comparator is used to compare binary tree nodes with each other.\n    this.nodeComparator = new Comparator();\n  }\n\n  /**\n   * @return {number}\n   */\n  get leftHeight() {\n    if (!this.left) {\n      return 0;\n    }\n\n    return this.left.height + 1;\n  }\n\n  /**\n   * @return {number}\n   */\n  get rightHeight() {\n    if (!this.right) {\n      return 0;\n    }\n\n    return this.right.height + 1;\n  }\n\n  /**\n   * @return {number}\n   */\n  get height() {\n    return Math.max(this.leftHeight, this.rightHeight);\n  }\n\n  /**\n   * @return {number}\n   */\n  get balanceFactor() {\n    return this.leftHeight - this.rightHeight;\n  }\n\n  /**\n   * Get parent's sibling if it exists.\n   * @return {BinaryTreeNode}\n   */\n  get uncle() {\n    // Check if current node has parent.\n    if (!this.parent) {\n      return undefined;\n    }\n\n    // Check if current node has grand-parent.\n    if (!this.parent.parent) {\n      return undefined;\n    }\n\n    // Check if grand-parent has two children.\n    if (!this.parent.parent.left || !this.parent.parent.right) {\n      return undefined;\n    }\n\n    // So for now we know that current node has grand-parent and this\n    // grand-parent has two children. Let's find out who is the uncle.\n    if (this.nodeComparator.equal(this.parent, this.parent.parent.left)) {\n      // Right one is an uncle.\n      return this.parent.parent.right;\n    }\n\n    // Left one is an uncle.\n    return this.parent.parent.left;\n  }\n\n  /**\n   * @param {*} value\n   * @return {BinaryTreeNode}\n   */\n  setValue(value) {\n    this.value = value;\n\n    return this;\n  }\n\n  /**\n   * @param {BinaryTreeNode} node\n   * @return {BinaryTreeNode}\n   */\n  setLeft(node) {\n    // Reset parent for left node since it is going to be detached.\n    if (this.left) {\n      this.left.parent = null;\n    }\n\n    // Attach new node to the left.\n    this.left = node;\n\n    // Make current node to be a parent for new left one.\n    if (this.left) {\n      this.left.parent = this;\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {BinaryTreeNode} node\n   * @return {BinaryTreeNode}\n   */\n  setRight(node) {\n    // Reset parent for right node since it is going to be detached.\n    if (this.right) {\n      this.right.parent = null;\n    }\n\n    // Attach new node to the right.\n    this.right = node;\n\n    // Make current node to be a parent for new right one.\n    if (node) {\n      this.right.parent = this;\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {BinaryTreeNode} nodeToRemove\n   * @return {boolean}\n   */\n  removeChild(nodeToRemove) {\n    if (this.left && this.nodeComparator.equal(this.left, nodeToRemove)) {\n      this.left = null;\n      return true;\n    }\n\n    if (this.right && this.nodeComparator.equal(this.right, nodeToRemove)) {\n      this.right = null;\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   * @param {BinaryTreeNode} nodeToReplace\n   * @param {BinaryTreeNode} replacementNode\n   * @return {boolean}\n   */\n  replaceChild(nodeToReplace, replacementNode) {\n    if (!nodeToReplace || !replacementNode) {\n      return false;\n    }\n\n    if (this.left && this.nodeComparator.equal(this.left, nodeToReplace)) {\n      this.left = replacementNode;\n      return true;\n    }\n\n    if (this.right && this.nodeComparator.equal(this.right, nodeToReplace)) {\n      this.right = replacementNode;\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   * @param {BinaryTreeNode} sourceNode\n   * @param {BinaryTreeNode} targetNode\n   */\n  static copyNode(sourceNode, targetNode) {\n    targetNode.setValue(sourceNode.value);\n    targetNode.setLeft(sourceNode.left);\n    targetNode.setRight(sourceNode.right);\n  }\n\n  /**\n   * @return {*[]}\n   */\n  traverseInOrder() {\n    let traverse = [];\n\n    // Add left node.\n    if (this.left) {\n      traverse = traverse.concat(this.left.traverseInOrder());\n    }\n\n    // Add root.\n    traverse.push(this.value);\n\n    // Add right node.\n    if (this.right) {\n      traverse = traverse.concat(this.right.traverseInOrder());\n    }\n\n    return traverse;\n  }\n\n  /**\n   * @return {string}\n   */\n  toString() {\n    return this.traverseInOrder().toString();\n  }\n}\n"
  },
  {
    "path": "src/data-structures/tree/README.md",
    "content": "# Tree\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Português_](README.pt-BR.md)\n\n* [Binary Search Tree](binary-search-tree)\n* [AVL Tree](avl-tree)\n* [Red-Black Tree](red-black-tree)\n* [Segment Tree](segment-tree) - with min/max/sum range queries examples\n* [Fenwick Tree](fenwick-tree) (Binary Indexed Tree)\n\nIn computer science, a **tree** is a widely used abstract data\ntype (ADT) — or data structure implementing this ADT—that\nsimulates a hierarchical tree structure, with a root value\nand subtrees of children with a parent node, represented as\na set of linked nodes.\n\nA tree data structure can be defined recursively (locally)\nas a collection of nodes (starting at a root node), where\neach node is a data structure consisting of a value,\ntogether with a list of references to nodes (the \"children\"),\nwith the constraints that no reference is duplicated, and none\npoints to the root.\n\nA simple unordered tree; in this diagram, the node labeled 3 has\ntwo children, labeled 2 and 6, and one parent, labeled 2. The\nroot node, at the top, has no parent.\n\n![Tree](./images/tree.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)\n"
  },
  {
    "path": "src/data-structures/tree/README.pt-BR.md",
    "content": "# Árvore (Tree)\n\n* [Árvore de Pesquisa Binária (Binary Search Tree)](binary-search-tree/README.pt-BR.md)\n* [Árvore AVL (AVL Tree)](avl-tree/README.pt-BR.md)\n* [Árvore Vermelha-Preta (Red-Black Tree)](red-black-tree/README.pt-BR.md)\n* [Árvore de Segmento (Segment Tree)](segment-tree/README.pt-BR.md) - com exemplos de consulta de intervalores min/max/sum\n* [Árvorem Fenwick (Fenwick Tree)](fenwick-tree/README.pt-BR.md) (Árvore Binária Indexada / Binary Indexed Tree)\n\nNa ciência da computação, uma **árvore** é uma estrutura de dados\nabstrada (ADT) amplamente utilizada - ou uma estrutura de dados\nimplementando este ADT que simula uma estrutura hierárquica de árvore,\ncom valor raíz e sub-árvores de filhos com um nó pai, representado\ncomo um conjunto de nós conectados.\n\nUma estrutura de dados em árvore pode ser definida recursivamente como\n(localmente) uma coleção de nós (começando no nó raíz), aonde cada nó\né uma estrutura de dados consistindo de um valor, junto com uma lista\nde referências aos nós (os \"filhos\"), com as restrições de que nenhuma\nreferência é duplicada e nenhuma aponta para a raiz.\n\nUma árvore não ordenada simples; neste diagrama, o nó rotulado como `7`\npossui dois filhos, rotulados como `2` e `6`, e um pai, rotulado como `2`.\nO nó raíz, no topo, não possui nenhum pai.\n\n![Tree](./images/tree.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)\n"
  },
  {
    "path": "src/data-structures/tree/README.zh-CN.md",
    "content": "# 树\n\n* [二叉搜索树](binary-search-tree)\n* [AVL树](avl-tree)\n* [红黑树](red-black-tree)\n* [线段树](segment-tree) - with min/max/sum range queries examples\n* [芬威克树/Fenwick Tree](fenwick-tree) (Binary Indexed Tree)\n\n在计算机科学中, **树(tree)** 是一种广泛使用的抽象数据类型(ADT)— 或实现此ADT的数据结构 — 模拟分层树结构, 具有根节点和有父节点的子树,表示为一组链接节点。\n\n树可以被(本地地)递归定义为一个(始于一个根节点的)节点集, 每个节点都是一个包含了值的数据结构, 除了值,还有该节点的节点引用列表(子节点)一起。\n树的节点之间没有引用重复的约束。\n\n一棵简单的无序树; 在下图中:\n\n标记为7的节点具有两个子节点, 标记为2和6;\n一个父节点,标记为2,作为根节点, 在顶部,没有父节点。\n\n![Tree](./images/tree.jpeg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure))\n- [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)\n"
  },
  {
    "path": "src/data-structures/tree/__test__/BinaryTreeNode.test.js",
    "content": "import BinaryTreeNode from '../BinaryTreeNode';\n\ndescribe('BinaryTreeNode', () => {\n  it('should create node', () => {\n    const node = new BinaryTreeNode();\n\n    expect(node).toBeDefined();\n\n    expect(node.value).toBeNull();\n    expect(node.left).toBeNull();\n    expect(node.right).toBeNull();\n\n    const leftNode = new BinaryTreeNode(1);\n    const rightNode = new BinaryTreeNode(3);\n    const rootNode = new BinaryTreeNode(2);\n\n    rootNode\n      .setLeft(leftNode)\n      .setRight(rightNode);\n\n    expect(rootNode.value).toBe(2);\n    expect(rootNode.left.value).toBe(1);\n    expect(rootNode.right.value).toBe(3);\n  });\n\n  it('should set parent', () => {\n    const leftNode = new BinaryTreeNode(1);\n    const rightNode = new BinaryTreeNode(3);\n    const rootNode = new BinaryTreeNode(2);\n\n    rootNode\n      .setLeft(leftNode)\n      .setRight(rightNode);\n\n    expect(rootNode.parent).toBeNull();\n    expect(rootNode.left.parent.value).toBe(2);\n    expect(rootNode.right.parent.value).toBe(2);\n    expect(rootNode.right.parent).toEqual(rootNode);\n  });\n\n  it('should traverse node', () => {\n    const leftNode = new BinaryTreeNode(1);\n    const rightNode = new BinaryTreeNode(3);\n    const rootNode = new BinaryTreeNode(2);\n\n    rootNode\n      .setLeft(leftNode)\n      .setRight(rightNode);\n\n    expect(rootNode.traverseInOrder()).toEqual([1, 2, 3]);\n\n    expect(rootNode.toString()).toBe('1,2,3');\n  });\n\n  it('should remove child node', () => {\n    const leftNode = new BinaryTreeNode(1);\n    const rightNode = new BinaryTreeNode(3);\n    const rootNode = new BinaryTreeNode(2);\n\n    rootNode\n      .setLeft(leftNode)\n      .setRight(rightNode);\n\n    expect(rootNode.traverseInOrder()).toEqual([1, 2, 3]);\n\n    expect(rootNode.removeChild(rootNode.left)).toBe(true);\n    expect(rootNode.traverseInOrder()).toEqual([2, 3]);\n\n    expect(rootNode.removeChild(rootNode.right)).toBe(true);\n    expect(rootNode.traverseInOrder()).toEqual([2]);\n\n    expect(rootNode.removeChild(rootNode.right)).toBe(false);\n    expect(rootNode.traverseInOrder()).toEqual([2]);\n  });\n\n  it('should replace child node', () => {\n    const leftNode = new BinaryTreeNode(1);\n    const rightNode = new BinaryTreeNode(3);\n    const rootNode = new BinaryTreeNode(2);\n\n    rootNode\n      .setLeft(leftNode)\n      .setRight(rightNode);\n\n    expect(rootNode.traverseInOrder()).toEqual([1, 2, 3]);\n\n    const replacementNode = new BinaryTreeNode(5);\n    rightNode.setRight(replacementNode);\n\n    expect(rootNode.traverseInOrder()).toEqual([1, 2, 3, 5]);\n\n    expect(rootNode.replaceChild(rootNode.right, rootNode.right.right)).toBe(true);\n    expect(rootNode.right.value).toBe(5);\n    expect(rootNode.right.right).toBeNull();\n    expect(rootNode.traverseInOrder()).toEqual([1, 2, 5]);\n\n    expect(rootNode.replaceChild(rootNode.right, rootNode.right.right)).toBe(false);\n    expect(rootNode.traverseInOrder()).toEqual([1, 2, 5]);\n\n    expect(rootNode.replaceChild(rootNode.right, replacementNode)).toBe(true);\n    expect(rootNode.traverseInOrder()).toEqual([1, 2, 5]);\n\n    expect(rootNode.replaceChild(rootNode.left, replacementNode)).toBe(true);\n    expect(rootNode.traverseInOrder()).toEqual([5, 2, 5]);\n\n    expect(rootNode.replaceChild(new BinaryTreeNode(), new BinaryTreeNode())).toBe(false);\n  });\n\n  it('should calculate node height', () => {\n    const root = new BinaryTreeNode(1);\n    const left = new BinaryTreeNode(3);\n    const right = new BinaryTreeNode(2);\n    const grandLeft = new BinaryTreeNode(5);\n    const grandRight = new BinaryTreeNode(6);\n    const grandGrandLeft = new BinaryTreeNode(7);\n\n    expect(root.height).toBe(0);\n    expect(root.balanceFactor).toBe(0);\n\n    root\n      .setLeft(left)\n      .setRight(right);\n\n    expect(root.height).toBe(1);\n    expect(left.height).toBe(0);\n    expect(root.balanceFactor).toBe(0);\n\n    left\n      .setLeft(grandLeft)\n      .setRight(grandRight);\n\n    expect(root.height).toBe(2);\n    expect(left.height).toBe(1);\n    expect(grandLeft.height).toBe(0);\n    expect(grandRight.height).toBe(0);\n    expect(root.balanceFactor).toBe(1);\n\n    grandLeft.setLeft(grandGrandLeft);\n\n    expect(root.height).toBe(3);\n    expect(left.height).toBe(2);\n    expect(grandLeft.height).toBe(1);\n    expect(grandRight.height).toBe(0);\n    expect(grandGrandLeft.height).toBe(0);\n    expect(root.balanceFactor).toBe(2);\n  });\n\n  it('should calculate node height for right nodes as well', () => {\n    const root = new BinaryTreeNode(1);\n    const right = new BinaryTreeNode(2);\n\n    root.setRight(right);\n\n    expect(root.height).toBe(1);\n    expect(right.height).toBe(0);\n    expect(root.balanceFactor).toBe(-1);\n  });\n\n  it('should set null for left and right node', () => {\n    const root = new BinaryTreeNode(2);\n    const left = new BinaryTreeNode(1);\n    const right = new BinaryTreeNode(3);\n\n    root.setLeft(left);\n    root.setRight(right);\n\n    expect(root.left.value).toBe(1);\n    expect(root.right.value).toBe(3);\n\n    root.setLeft(null);\n    root.setRight(null);\n\n    expect(root.left).toBeNull();\n    expect(root.right).toBeNull();\n  });\n\n  it('should be possible to create node with object as a value', () => {\n    const obj1 = { key: 'object_1', toString: () => 'object_1' };\n    const obj2 = { key: 'object_2' };\n\n    const node1 = new BinaryTreeNode(obj1);\n    const node2 = new BinaryTreeNode(obj2);\n\n    node1.setLeft(node2);\n\n    expect(node1.value).toEqual(obj1);\n    expect(node2.value).toEqual(obj2);\n    expect(node1.left.value).toEqual(obj2);\n\n    node1.removeChild(node2);\n\n    expect(node1.value).toEqual(obj1);\n    expect(node2.value).toEqual(obj2);\n    expect(node1.left).toBeNull();\n\n    expect(node1.toString()).toBe('object_1');\n    expect(node2.toString()).toBe('[object Object]');\n  });\n\n  it('should be possible to attach meta information to the node', () => {\n    const redNode = new BinaryTreeNode(1);\n    const blackNode = new BinaryTreeNode(2);\n\n    redNode.meta.set('color', 'red');\n    blackNode.meta.set('color', 'black');\n\n    expect(redNode.meta.get('color')).toBe('red');\n    expect(blackNode.meta.get('color')).toBe('black');\n  });\n\n  it('should detect right uncle', () => {\n    const grandParent = new BinaryTreeNode('grand-parent');\n    const parent = new BinaryTreeNode('parent');\n    const uncle = new BinaryTreeNode('uncle');\n    const child = new BinaryTreeNode('child');\n\n    expect(grandParent.uncle).not.toBeDefined();\n    expect(parent.uncle).not.toBeDefined();\n\n    grandParent.setLeft(parent);\n\n    expect(parent.uncle).not.toBeDefined();\n    expect(child.uncle).not.toBeDefined();\n\n    parent.setLeft(child);\n\n    expect(child.uncle).not.toBeDefined();\n\n    grandParent.setRight(uncle);\n\n    expect(parent.uncle).not.toBeDefined();\n    expect(child.uncle).toBeDefined();\n    expect(child.uncle).toEqual(uncle);\n  });\n\n  it('should detect left uncle', () => {\n    const grandParent = new BinaryTreeNode('grand-parent');\n    const parent = new BinaryTreeNode('parent');\n    const uncle = new BinaryTreeNode('uncle');\n    const child = new BinaryTreeNode('child');\n\n    expect(grandParent.uncle).not.toBeDefined();\n    expect(parent.uncle).not.toBeDefined();\n\n    grandParent.setRight(parent);\n\n    expect(parent.uncle).not.toBeDefined();\n    expect(child.uncle).not.toBeDefined();\n\n    parent.setRight(child);\n\n    expect(child.uncle).not.toBeDefined();\n\n    grandParent.setLeft(uncle);\n\n    expect(parent.uncle).not.toBeDefined();\n    expect(child.uncle).toBeDefined();\n    expect(child.uncle).toEqual(uncle);\n  });\n\n  it('should be possible to set node values', () => {\n    const node = new BinaryTreeNode('initial_value');\n\n    expect(node.value).toBe('initial_value');\n\n    node.setValue('new_value');\n\n    expect(node.value).toBe('new_value');\n  });\n\n  it('should be possible to copy node', () => {\n    const root = new BinaryTreeNode('root');\n    const left = new BinaryTreeNode('left');\n    const right = new BinaryTreeNode('right');\n\n    root\n      .setLeft(left)\n      .setRight(right);\n\n    expect(root.toString()).toBe('left,root,right');\n\n    const newRoot = new BinaryTreeNode('new_root');\n    const newLeft = new BinaryTreeNode('new_left');\n    const newRight = new BinaryTreeNode('new_right');\n\n    newRoot\n      .setLeft(newLeft)\n      .setRight(newRight);\n\n    expect(newRoot.toString()).toBe('new_left,new_root,new_right');\n\n    BinaryTreeNode.copyNode(root, newRoot);\n\n    expect(root.toString()).toBe('left,root,right');\n    expect(newRoot.toString()).toBe('left,root,right');\n  });\n});\n"
  },
  {
    "path": "src/data-structures/tree/avl-tree/AvlTree.js",
    "content": "import BinarySearchTree from '../binary-search-tree/BinarySearchTree';\n\nexport default class AvlTree extends BinarySearchTree {\n  /**\n   * @param {*} value\n   */\n  insert(value) {\n    // Do the normal BST insert.\n    super.insert(value);\n\n    // Let's move up to the root and check balance factors along the way.\n    let currentNode = this.root.find(value);\n    while (currentNode) {\n      this.balance(currentNode);\n      currentNode = currentNode.parent;\n    }\n  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  remove(value) {\n    // Do standard BST removal.\n    super.remove(value);\n\n    // Balance the tree starting from the root node.\n    this.balance(this.root);\n  }\n\n  /**\n   * @param {BinarySearchTreeNode} node\n   */\n  balance(node) {\n    // If balance factor is not OK then try to balance the node.\n    if (node.balanceFactor > 1) {\n      // Left rotation.\n      if (node.left.balanceFactor > 0) {\n        // Left-Left rotation\n        this.rotateLeftLeft(node);\n      } else if (node.left.balanceFactor < 0) {\n        // Left-Right rotation.\n        this.rotateLeftRight(node);\n      }\n    } else if (node.balanceFactor < -1) {\n      // Right rotation.\n      if (node.right.balanceFactor < 0) {\n        // Right-Right rotation\n        this.rotateRightRight(node);\n      } else if (node.right.balanceFactor > 0) {\n        // Right-Left rotation.\n        this.rotateRightLeft(node);\n      }\n    }\n  }\n\n  /**\n   * @param {BinarySearchTreeNode} rootNode\n   */\n  rotateLeftLeft(rootNode) {\n    // Detach left node from root node.\n    const leftNode = rootNode.left;\n    rootNode.setLeft(null);\n\n    // Make left node to be a child of rootNode's parent.\n    if (rootNode.parent) {\n      rootNode.parent.setLeft(leftNode);\n    } else if (rootNode === this.root) {\n      // If root node is root then make left node to be a new root.\n      this.root = leftNode;\n    }\n\n    // If left node has a right child then detach it and\n    // attach it as a left child for rootNode.\n    if (leftNode.right) {\n      rootNode.setLeft(leftNode.right);\n    }\n\n    // Attach rootNode to the right of leftNode.\n    leftNode.setRight(rootNode);\n  }\n\n  /**\n   * @param {BinarySearchTreeNode} rootNode\n   */\n  rotateLeftRight(rootNode) {\n    // Detach left node from rootNode since it is going to be replaced.\n    const leftNode = rootNode.left;\n    rootNode.setLeft(null);\n\n    // Detach right node from leftNode.\n    const leftRightNode = leftNode.right;\n    leftNode.setRight(null);\n\n    // Preserve leftRightNode's left subtree.\n    if (leftRightNode.left) {\n      leftNode.setRight(leftRightNode.left);\n      leftRightNode.setLeft(null);\n    }\n\n    // Attach leftRightNode to the rootNode.\n    rootNode.setLeft(leftRightNode);\n\n    // Attach leftNode as left node for leftRight node.\n    leftRightNode.setLeft(leftNode);\n\n    // Do left-left rotation.\n    this.rotateLeftLeft(rootNode);\n  }\n\n  /**\n   * @param {BinarySearchTreeNode} rootNode\n   */\n  rotateRightLeft(rootNode) {\n    // Detach right node from rootNode since it is going to be replaced.\n    const rightNode = rootNode.right;\n    rootNode.setRight(null);\n\n    // Detach left node from rightNode.\n    const rightLeftNode = rightNode.left;\n    rightNode.setLeft(null);\n\n    if (rightLeftNode.right) {\n      rightNode.setLeft(rightLeftNode.right);\n      rightLeftNode.setRight(null);\n    }\n\n    // Attach rightLeftNode to the rootNode.\n    rootNode.setRight(rightLeftNode);\n\n    // Attach rightNode as right node for rightLeft node.\n    rightLeftNode.setRight(rightNode);\n\n    // Do right-right rotation.\n    this.rotateRightRight(rootNode);\n  }\n\n  /**\n   * @param {BinarySearchTreeNode} rootNode\n   */\n  rotateRightRight(rootNode) {\n    // Detach right node from root node.\n    const rightNode = rootNode.right;\n    rootNode.setRight(null);\n\n    // Make right node to be a child of rootNode's parent.\n    if (rootNode.parent) {\n      rootNode.parent.setRight(rightNode);\n    } else if (rootNode === this.root) {\n      // If root node is root then make right node to be a new root.\n      this.root = rightNode;\n    }\n\n    // If right node has a left child then detach it and\n    // attach it as a right child for rootNode.\n    if (rightNode.left) {\n      rootNode.setRight(rightNode.left);\n    }\n\n    // Attach rootNode to the left of rightNode.\n    rightNode.setLeft(rootNode);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/tree/avl-tree/README.md",
    "content": "# AVL Tree\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nIn computer science, an **AVL tree** (named after inventors \nAdelson-Velsky and Landis) is a self-balancing binary search \ntree. It was the first such data structure to be invented. \nIn an AVL tree, the heights of the two child subtrees of any\nnode differ by at most one; if at any time they differ by \nmore than one, rebalancing is done to restore this property.\nLookup, insertion, and deletion all take `O(log n)` time in \nboth the average and worst cases, where n is the number of \nnodes in the tree prior to the operation. Insertions and \ndeletions may require the tree to be rebalanced by one or \nmore tree rotations.\n\nAnimation showing the insertion of several elements into an AVL \ntree. It includes left, right, left-right and right-left rotations.\n\n![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/f/fd/AVL_Tree_Example.gif)\n\nAVL tree with balance factors (green)\n\n![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/a/ad/AVL-tree-wBalance_K.svg)\n\n### AVL Tree Rotations\n\n**Left-Left Rotation**\n\n![Left-Left Rotation](http://btechsmartclass.com/data_structures/ds_images/LL%20Rotation.png)\n\n**Right-Right Rotation**\n\n![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RR%20Rotation.png)\n\n**Left-Right Rotation**\n\n![Left-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/LR%20Rotation.png)\n\n**Right-Left Rotation**\n\n![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RL%20Rotation.png)\n\n## References\n\n* [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree)\n* [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm)\n* [BTech](http://btechsmartclass.com/data_structures/avl-trees.html)\n* [AVL Tree Insertion on YouTube](https://www.youtube.com/watch?v=rbg7Qf8GkQ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=12&)\n* [AVL Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)\n"
  },
  {
    "path": "src/data-structures/tree/avl-tree/README.pt-BR.md",
    "content": "# Árvore AVL (AVL Tree)\n\nNa ciência da computação, uma **árvore AVL** (em homenagem aos\ninventores Adelson-Velsky e Landis) é uma árvore de pesquisa\nbinária auto balanceada. Foi a primeira estrutura de dados a\nser inventada.\nEm uma árvore AVL, as alturas de duas sub-árvores filhas\nde qualquer nó diferem no máximo em um; se a qualquer momento\ndiferirem por em mais de um, um rebalanceamento é feito para\nrestaurar esta propriedade.\nPesquisa, inserção e exclusão possuem tempo `O(log n)` tanto na\nmédia quanto nos piores casos, onde `n` é o número de nós na\nárvore antes da operação. Inserções e exclusões podem exigir\nque a árvore seja reequilibrada por uma ou mais rotações.\n\n\nAnimação mostrando a inserção de vários elementos em uma árvore AVL.\nInclui as rotações de esquerda, direita, esquerda-direita e direita-esquerda.\n\n![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/f/fd/AVL_Tree_Example.gif)\n\nÁrvore AVL com fatores de equilíbrio (verde)\n\n![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/a/ad/AVL-tree-wBalance_K.svg)\n\n### Rotações de Árvores AVL\n\n**Rotação Esquerda-Esquerda**\n\n![Left-Left Rotation](http://btechsmartclass.com/data_structures/ds_images/LL%20Rotation.png)\n\n**Rotação direita-direita**\n\n![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RR%20Rotation.png)\n\n**Rotação Esquerda-Direita**\n\n![Left-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/LR%20Rotation.png)\n\n**Rotação Direita-Esquerda**\n\n![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RL%20Rotation.png)\n\n## Referências\n\n* [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree)\n* [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm)\n* [BTech](http://btechsmartclass.com/data_structures/avl-trees.html)\n* [AVL Tree Insertion on YouTube](https://www.youtube.com/watch?v=rbg7Qf8GkQ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=12&)\n* [AVL Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)\n"
  },
  {
    "path": "src/data-structures/tree/avl-tree/__test__/AvlTRee.test.js",
    "content": "import AvlTree from '../AvlTree';\n\ndescribe('AvlTree', () => {\n  it('should do simple left-left rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(4);\n    tree.insert(3);\n    tree.insert(2);\n\n    expect(tree.toString()).toBe('2,3,4');\n    expect(tree.root.value).toBe(3);\n    expect(tree.root.height).toBe(1);\n\n    tree.insert(1);\n\n    expect(tree.toString()).toBe('1,2,3,4');\n    expect(tree.root.value).toBe(3);\n    expect(tree.root.height).toBe(2);\n\n    tree.insert(0);\n\n    expect(tree.toString()).toBe('0,1,2,3,4');\n    expect(tree.root.value).toBe(3);\n    expect(tree.root.left.value).toBe(1);\n    expect(tree.root.height).toBe(2);\n  });\n\n  it('should do complex left-left rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(30);\n    tree.insert(20);\n    tree.insert(40);\n    tree.insert(10);\n\n    expect(tree.root.value).toBe(30);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('10,20,30,40');\n\n    tree.insert(25);\n    expect(tree.root.value).toBe(30);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('10,20,25,30,40');\n\n    tree.insert(5);\n    expect(tree.root.value).toBe(20);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('5,10,20,25,30,40');\n  });\n\n  it('should do simple right-right rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(2);\n    tree.insert(3);\n    tree.insert(4);\n\n    expect(tree.toString()).toBe('2,3,4');\n    expect(tree.root.value).toBe(3);\n    expect(tree.root.height).toBe(1);\n\n    tree.insert(5);\n\n    expect(tree.toString()).toBe('2,3,4,5');\n    expect(tree.root.value).toBe(3);\n    expect(tree.root.height).toBe(2);\n\n    tree.insert(6);\n\n    expect(tree.toString()).toBe('2,3,4,5,6');\n    expect(tree.root.value).toBe(3);\n    expect(tree.root.right.value).toBe(5);\n    expect(tree.root.height).toBe(2);\n  });\n\n  it('should do complex right-right rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(30);\n    tree.insert(20);\n    tree.insert(40);\n    tree.insert(50);\n\n    expect(tree.root.value).toBe(30);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('20,30,40,50');\n\n    tree.insert(35);\n    expect(tree.root.value).toBe(30);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('20,30,35,40,50');\n\n    tree.insert(55);\n    expect(tree.root.value).toBe(40);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('20,30,35,40,50,55');\n  });\n\n  it('should do left-right rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(30);\n    tree.insert(20);\n    tree.insert(25);\n\n    expect(tree.root.height).toBe(1);\n    expect(tree.root.value).toBe(25);\n    expect(tree.toString()).toBe('20,25,30');\n  });\n\n  it('should do right-left rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(30);\n    tree.insert(40);\n    tree.insert(35);\n\n    expect(tree.root.height).toBe(1);\n    expect(tree.root.value).toBe(35);\n    expect(tree.toString()).toBe('30,35,40');\n  });\n\n  it('should create balanced tree: case #1', () => {\n    // @see: https://www.youtube.com/watch?v=rbg7Qf8GkQ4&t=839s\n    const tree = new AvlTree();\n\n    tree.insert(1);\n    tree.insert(2);\n    tree.insert(3);\n\n    expect(tree.root.value).toBe(2);\n    expect(tree.root.height).toBe(1);\n    expect(tree.toString()).toBe('1,2,3');\n\n    tree.insert(6);\n\n    expect(tree.root.value).toBe(2);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('1,2,3,6');\n\n    tree.insert(15);\n\n    expect(tree.root.value).toBe(2);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('1,2,3,6,15');\n\n    tree.insert(-2);\n\n    expect(tree.root.value).toBe(2);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('-2,1,2,3,6,15');\n\n    tree.insert(-5);\n\n    expect(tree.root.value).toBe(2);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('-5,-2,1,2,3,6,15');\n\n    tree.insert(-8);\n\n    expect(tree.root.value).toBe(2);\n    expect(tree.root.height).toBe(3);\n    expect(tree.toString()).toBe('-8,-5,-2,1,2,3,6,15');\n  });\n\n  it('should create balanced tree: case #2', () => {\n    // @see https://www.youtube.com/watch?v=7m94k2Qhg68\n    const tree = new AvlTree();\n\n    tree.insert(43);\n    tree.insert(18);\n    tree.insert(22);\n    tree.insert(9);\n    tree.insert(21);\n    tree.insert(6);\n\n    expect(tree.root.value).toBe(18);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('6,9,18,21,22,43');\n\n    tree.insert(8);\n\n    expect(tree.root.value).toBe(18);\n    expect(tree.root.height).toBe(2);\n    expect(tree.toString()).toBe('6,8,9,18,21,22,43');\n  });\n\n  it('should do left right rotation and keeping left right node safe', () => {\n    const tree = new AvlTree();\n\n    tree.insert(30);\n    tree.insert(15);\n    tree.insert(40);\n    tree.insert(10);\n    tree.insert(18);\n    tree.insert(35);\n    tree.insert(45);\n    tree.insert(5);\n    tree.insert(12);\n\n    expect(tree.toString()).toBe('5,10,12,15,18,30,35,40,45');\n    expect(tree.root.height).toBe(3);\n\n    tree.insert(11);\n\n    expect(tree.toString()).toBe('5,10,11,12,15,18,30,35,40,45');\n    expect(tree.root.height).toBe(3);\n  });\n\n  it('should do left right rotation and keeping left right node safe', () => {\n    const tree = new AvlTree();\n\n    tree.insert(30);\n    tree.insert(15);\n    tree.insert(40);\n    tree.insert(10);\n    tree.insert(18);\n    tree.insert(35);\n    tree.insert(45);\n    tree.insert(42);\n    tree.insert(47);\n\n    expect(tree.toString()).toBe('10,15,18,30,35,40,42,45,47');\n    expect(tree.root.height).toBe(3);\n\n    tree.insert(43);\n\n    expect(tree.toString()).toBe('10,15,18,30,35,40,42,43,45,47');\n    expect(tree.root.height).toBe(3);\n  });\n\n  it('should remove values from the tree with right-right rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(10);\n    tree.insert(20);\n    tree.insert(30);\n    tree.insert(40);\n\n    expect(tree.toString()).toBe('10,20,30,40');\n\n    tree.remove(10);\n\n    expect(tree.toString()).toBe('20,30,40');\n    expect(tree.root.value).toBe(30);\n    expect(tree.root.left.value).toBe(20);\n    expect(tree.root.right.value).toBe(40);\n    expect(tree.root.balanceFactor).toBe(0);\n  });\n\n  it('should remove values from the tree with left-left rotation', () => {\n    const tree = new AvlTree();\n\n    tree.insert(10);\n    tree.insert(20);\n    tree.insert(30);\n    tree.insert(5);\n\n    expect(tree.toString()).toBe('5,10,20,30');\n\n    tree.remove(30);\n\n    expect(tree.toString()).toBe('5,10,20');\n    expect(tree.root.value).toBe(10);\n    expect(tree.root.left.value).toBe(5);\n    expect(tree.root.right.value).toBe(20);\n    expect(tree.root.balanceFactor).toBe(0);\n  });\n\n  it('should keep balance after removal', () => {\n    const tree = new AvlTree();\n\n    tree.insert(1);\n    tree.insert(2);\n    tree.insert(3);\n    tree.insert(4);\n    tree.insert(5);\n    tree.insert(6);\n    tree.insert(7);\n    tree.insert(8);\n    tree.insert(9);\n\n    expect(tree.toString()).toBe('1,2,3,4,5,6,7,8,9');\n    expect(tree.root.value).toBe(4);\n    expect(tree.root.height).toBe(3);\n    expect(tree.root.balanceFactor).toBe(-1);\n\n    tree.remove(8);\n\n    expect(tree.root.value).toBe(4);\n    expect(tree.root.balanceFactor).toBe(-1);\n\n    tree.remove(9);\n\n    expect(tree.contains(8)).toBeFalsy();\n    expect(tree.contains(9)).toBeFalsy();\n    expect(tree.toString()).toBe('1,2,3,4,5,6,7');\n    expect(tree.root.value).toBe(4);\n    expect(tree.root.height).toBe(2);\n    expect(tree.root.balanceFactor).toBe(0);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/tree/binary-search-tree/BinarySearchTree.js",
    "content": "import BinarySearchTreeNode from './BinarySearchTreeNode';\n\nexport default class BinarySearchTree {\n  /**\n   * @param {function} [nodeValueCompareFunction]\n   */\n  constructor(nodeValueCompareFunction) {\n    this.root = new BinarySearchTreeNode(null, nodeValueCompareFunction);\n\n    // Steal node comparator from the root.\n    this.nodeComparator = this.root.nodeComparator;\n  }\n\n  /**\n   * @param {*} value\n   * @return {BinarySearchTreeNode}\n   */\n  insert(value) {\n    return this.root.insert(value);\n  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  contains(value) {\n    return this.root.contains(value);\n  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  remove(value) {\n    return this.root.remove(value);\n  }\n\n  /**\n   * @return {string}\n   */\n  toString() {\n    return this.root.toString();\n  }\n}\n"
  },
  {
    "path": "src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js",
    "content": "import BinaryTreeNode from '../BinaryTreeNode';\nimport Comparator from '../../../utils/comparator/Comparator';\n\nexport default class BinarySearchTreeNode extends BinaryTreeNode {\n  /**\n   * @param {*} [value] - node value.\n   * @param {function} [compareFunction] - comparator function for node values.\n   */\n  constructor(value = null, compareFunction = undefined) {\n    super(value);\n\n    // This comparator is used to compare node values with each other.\n    this.compareFunction = compareFunction;\n    this.nodeValueComparator = new Comparator(compareFunction);\n  }\n\n  /**\n   * @param {*} value\n   * @return {BinarySearchTreeNode}\n   */\n  insert(value) {\n    if (this.nodeValueComparator.equal(this.value, null)) {\n      this.value = value;\n\n      return this;\n    }\n\n    if (this.nodeValueComparator.lessThan(value, this.value)) {\n      // Insert to the left.\n      if (this.left) {\n        return this.left.insert(value);\n      }\n\n      const newNode = new BinarySearchTreeNode(value, this.compareFunction);\n      this.setLeft(newNode);\n\n      return newNode;\n    }\n\n    if (this.nodeValueComparator.greaterThan(value, this.value)) {\n      // Insert to the right.\n      if (this.right) {\n        return this.right.insert(value);\n      }\n\n      const newNode = new BinarySearchTreeNode(value, this.compareFunction);\n      this.setRight(newNode);\n\n      return newNode;\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {*} value\n   * @return {BinarySearchTreeNode}\n   */\n  find(value) {\n    // Check the root.\n    if (this.nodeValueComparator.equal(this.value, value)) {\n      return this;\n    }\n\n    if (this.nodeValueComparator.lessThan(value, this.value) && this.left) {\n      // Check left nodes.\n      return this.left.find(value);\n    }\n\n    if (this.nodeValueComparator.greaterThan(value, this.value) && this.right) {\n      // Check right nodes.\n      return this.right.find(value);\n    }\n\n    return null;\n  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  contains(value) {\n    return !!this.find(value);\n  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  remove(value) {\n    const nodeToRemove = this.find(value);\n\n    if (!nodeToRemove) {\n      throw new Error('Item not found in the tree');\n    }\n\n    const { parent } = nodeToRemove;\n\n    if (!nodeToRemove.left && !nodeToRemove.right) {\n      // Node is a leaf and thus has no children.\n      if (parent) {\n        // Node has a parent. Just remove the pointer to this node from the parent.\n        parent.removeChild(nodeToRemove);\n      } else {\n        // Node has no parent. Just erase current node value.\n        nodeToRemove.setValue(undefined);\n      }\n    } else if (nodeToRemove.left && nodeToRemove.right) {\n      // Node has two children.\n      // Find the next biggest value (minimum value in the right branch)\n      // and replace current value node with that next biggest value.\n      const nextBiggerNode = nodeToRemove.right.findMin();\n      if (!this.nodeComparator.equal(nextBiggerNode, nodeToRemove.right)) {\n        this.remove(nextBiggerNode.value);\n        nodeToRemove.setValue(nextBiggerNode.value);\n      } else {\n        // In case if next right value is the next bigger one and it doesn't have left child\n        // then just replace node that is going to be deleted with the right node.\n        nodeToRemove.setValue(nodeToRemove.right.value);\n        nodeToRemove.setRight(nodeToRemove.right.right);\n      }\n    } else {\n      // Node has only one child.\n      // Make this child to be a direct child of current node's parent.\n      /** @var BinarySearchTreeNode */\n      const childNode = nodeToRemove.left || nodeToRemove.right;\n\n      if (parent) {\n        parent.replaceChild(nodeToRemove, childNode);\n      } else {\n        BinaryTreeNode.copyNode(childNode, nodeToRemove);\n      }\n    }\n\n    // Clear the parent of removed node.\n    nodeToRemove.parent = null;\n\n    return true;\n  }\n\n  /**\n   * @return {BinarySearchTreeNode}\n   */\n  findMin() {\n    if (!this.left) {\n      return this;\n    }\n\n    return this.left.findMin();\n  }\n}\n"
  },
  {
    "path": "src/data-structures/tree/binary-search-tree/README.md",
    "content": "# Binary Search Tree\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md)\n\nIn computer science, **binary search trees** (BST), sometimes called\nordered or sorted binary trees, are a particular type of container:\ndata structures that store \"items\" (such as numbers, names etc.)\nin memory. They allow fast lookup, addition and removal of\nitems, and can be used to implement either dynamic sets of\nitems, or lookup tables that allow finding an item by its key\n(e.g., finding the phone number of a person by name).\n\nBinary search trees keep their keys in sorted order, so that lookup\nand other operations can use the principle of binary search:\nwhen looking for a key in a tree (or a place to insert a new key),\nthey traverse the tree from root to leaf, making comparisons to\nkeys stored in the nodes of the tree and deciding, on the basis\nof the comparison, to continue searching in the left or right\nsubtrees. On average, this means that each comparison allows\nthe operations to skip about half of the tree, so that each\nlookup, insertion or deletion takes time proportional to the\nlogarithm of the number of items stored in the tree. This is\nmuch better than the linear time required to find items by key\nin an (unsorted) array, but slower than the corresponding\noperations on hash tables.\n\nA binary search tree of size 9 and depth 3, with 8 at the root.\nThe leaves are not drawn.\n\n![Trie](./images/binary-search-tree.jpg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Pseudocode for Basic Operations\n\n### Insertion\n\n```text\ninsert(value)\n  Pre: value has passed custom type checks for type T\n  Post: value has been placed in the correct location in the tree\n  if root = ø\n    root ← node(value)\n  else\n    insertNode(root, value)\n  end if\nend insert\n```\n\n```text\ninsertNode(current, value)\n  Pre: current is the node to start from\n  Post: value has been placed in the correct location in the tree\n  if value < current.value\n    if current.left = ø\n      current.left ← node(value)\n    else\n      InsertNode(current.left, value)\n    end if\n  else\n    if current.right = ø\n      current.right ← node(value)\n    else\n      InsertNode(current.right, value)\n    end if\n  end if\nend insertNode\n```\n\n### Searching\n\n```text\ncontains(root, value)\n  Pre: root is the root node of the tree, value is what we would like to locate\n  Post: value is either located or not\n  if root = ø\n    return false\n  end if\n  if root.value = value\n    return true\n  else if value < root.value\n    return contains(root.left, value)\n  else\n    return contains(root.right, value)\n  end if\nend contains\n```\n\n\n### Deletion\n\n```text\nremove(value)\n  Pre: value is the value of the node to remove, root is the node of the BST\n      count is the number of items in the BST\n  Post: node with value is removed if found in which case yields true, otherwise false\n  nodeToRemove ← findNode(value)\n  if nodeToRemove = ø\n    return false\n  end if\n  parent ← findParent(value)\n  if count = 1\n    root ← ø\n  else if nodeToRemove.left = ø and nodeToRemove.right = ø\n    if nodeToRemove.value < parent.value\n      parent.left ←  nodeToRemove.right\n    else\n      parent.right ← nodeToRemove.right\n    end if\n  else if nodeToRemove.left != ø and nodeToRemove.right != ø\n    next ← nodeToRemove.right\n    while next.left != ø\n      next ← next.left\n    end while\n    if next != nodeToRemove.right\n      remove(next.value)\n      nodeToRemove.value ← next.value\n    else\n      nodeToRemove.value ← next.value\n      nodeToRemove.right ← nodeToRemove.right.right\n    end if\n  else\n    if nodeToRemove.left = ø\n      next ← nodeToRemove.right\n    else\n      next ← nodeToRemove.left\n    end if\n    if root = nodeToRemove\n      root = next\n    else if parent.left = nodeToRemove\n      parent.left = next\n    else if parent.right = nodeToRemove\n      parent.right = next\n    end if\n  end if\n  count ← count - 1\n  return true\nend remove\n```\n\n### Find Parent of Node\n\n```text\nfindParent(value, root)\n  Pre: value is the value of the node we want to find the parent of\n       root is the root node of the BST and is != ø\n  Post: a reference to the prent node of value if found; otherwise ø\n  if value = root.value\n    return ø\n  end if\n  if value < root.value\n    if root.left = ø\n      return ø\n    else if root.left.value = value\n      return root\n    else\n      return findParent(value, root.left)\n    end if\n  else\n    if root.right = ø\n      return ø\n    else if root.right.value = value\n      return root\n    else\n      return findParent(value, root.right)\n    end if\n  end if\nend findParent\n```\n\n### Find Node\n\n```text\nfindNode(root, value)\n  Pre: value is the value of the node we want to find the parent of\n       root is the root node of the BST\n  Post: a reference to the node of value if found; otherwise ø\n  if root = ø\n    return ø\n  end if\n  if root.value = value\n    return root\n  else if value < root.value\n    return findNode(root.left, value)\n  else\n    return findNode(root.right, value)\n  end if\nend findNode\n```\n\n### Find Minimum\n\n```text\nfindMin(root)\n  Pre: root is the root node of the BST\n    root = ø\n  Post: the smallest value in the BST is located\n  if root.left = ø\n    return root.value\n  end if\n  findMin(root.left)\nend findMin\n```\n\n### Find Maximum\n\n```text\nfindMax(root)\n  Pre: root is the root node of the BST\n    root = ø\n  Post: the largest value in the BST is located\n  if root.right = ø\n    return root.value\n  end if\n  findMax(root.right)\nend findMax\n```\n\n### Traversal\n\n#### InOrder Traversal\n\n```text\ninorder(root)\n  Pre: root is the root node of the BST\n  Post: the nodes in the BST have been visited in inorder\n  if root != ø\n    inorder(root.left)\n    yield root.value\n    inorder(root.right)\n  end if\nend inorder\n```\n\n#### PreOrder Traversal\n\n```text\npreorder(root)\n  Pre: root is the root node of the BST\n  Post: the nodes in the BST have been visited in preorder\n  if root != ø\n    yield root.value\n    preorder(root.left)\n    preorder(root.right)\n  end if\nend preorder\n```\n\n#### PostOrder Traversal\n\n```text\npostorder(root)\n  Pre: root is the root node of the BST\n  Post: the nodes in the BST have been visited in postorder\n  if root != ø\n    postorder(root.left)\n    postorder(root.right)\n    yield root.value\n  end if\nend postorder\n```\n\n## Complexities\n\n### Time Complexity\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) |\n\n### Space Complexity\n\nO(n)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_tree)\n- [Inserting to BST on YouTube](https://www.youtube.com/watch?v=wcIRPqTR3Kc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=9&t=0s)\n- [BST Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/BST.html)\n"
  },
  {
    "path": "src/data-structures/tree/binary-search-tree/README.pt-BR.md",
    "content": "# Árvore de Pesquisa Binária (Binary Search Tree)\n\nNa ciência da computação **binary search trees** (BST), algumas vezes\nchamadas de árvores binárias ordenadas (_ordered or sorted binary trees_),\né um tipo particular de container: estruturas de dados que armazenam\n\"itens\" (como números, nomes, etc.) na memória. Permite pesquisa rápida,\nadição e remoção de itens além de poder ser utilizado para implementar\ntanto conjuntos dinâmicos de itens ou, consultar tabelas que permitem\nencontrar um item por seu valor chave. E.g. encontrar o número de\ntelefone de uma pessoa pelo seu nome.\n\nÁrvore de Pesquisa Binária mantem seus valores chaves ordenados, para\nque uma pesquisa e outras operações possam usar o princípio da pesquisa\nbinária: quando pesquisando por um valor chave na árvore (ou um lugar\npara inserir uma nova chave), eles atravessam a árvore da raiz para a folha,\nfazendo comparações com chaves armazenadas nos nós da árvore e decidindo então,\ncom base nas comparações, continuar pesquisando nas sub-árvores a direita ou\na esquerda. Em média isto significa que cara comparação permite as operações\npular metade da árvore, para que então, cada pesquisa, inserção ou remoção\nconsuma tempo proporcional ao logaritmo do número de itens armazenados na\nárvore. Isto é muito melhor do que um tempo linear necessário para encontrar\nitens por seu valor chave em um array (desorndenado - _unsorted_), mas muito\nmais lento do que operações similares em tableas de hash (_hash tables_).\n\nUma pesquisa de árvore binária de tamanho 9 e profundidade 3, com valor 8\nna raíz.\nAs folhas não foram desenhadas.\n\n![Trie](./images/binary-search-tree.jpg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Pseudocódigo para Operações Básicas\n\n### Inserção\n\n```text\ninsert(value)\n  Pre: value has passed custom type checks for type T\n  Post: value has been placed in the correct location in the tree\n  if root = ø\n    root ← node(value)\n  else\n    insertNode(root, value)\n  end if\nend insert\n```\n\n```text\ninsertNode(current, value)\n  Pre: current is the node to start from\n  Post: value has been placed in the correct location in the tree\n  if value < current.value\n    if current.left = ø\n      current.left ← node(value)\n    else\n      InsertNode(current.left, value)\n    end if\n  else\n    if current.right = ø\n      current.right ← node(value)\n    else\n      InsertNode(current.right, value)\n    end if\n  end if\nend insertNode\n```\n\n### Pesquisa\n\n```text\ncontains(root, value)\n  Pre: root is the root node of the tree, value is what we would like to locate\n  Post: value is either located or not\n  if root = ø\n    return false\n  end if\n  if root.value = value\n    return true\n  else if value < root.value\n    return contains(root.left, value)\n  else\n    return contains(root.right, value)\n  end if\nend contains\n```\n\n\n### Remoção\n\n```text\nremove(value)\n  Pre: value is the value of the node to remove, root is the node of the BST\n      count is the number of items in the BST\n  Post: node with value is removed if found in which case yields true, otherwise false\n  nodeToRemove ← findNode(value)\n  if nodeToRemove = ø\n    return false\n  end if\n  parent ← findParent(value)\n  if count = 1\n    root ← ø\n  else if nodeToRemove.left = ø and nodeToRemove.right = ø\n    if nodeToRemove.value < parent.value\n      parent.left ←  nodeToRemove.right\n    else\n      parent.right ← nodeToRemove.right\n    end if\n  else if nodeToRemove.left != ø and nodeToRemove.right != ø\n    next ← nodeToRemove.right\n    while next.left != ø\n      next ← next.left\n    end while\n    if next != nodeToRemove.right\n      remove(next.value)\n      nodeToRemove.value ← next.value\n    else\n      nodeToRemove.value ← next.value\n      nodeToRemove.right ← nodeToRemove.right.right\n    end if\n  else\n    if nodeToRemove.left = ø\n      next ← nodeToRemove.right\n    else\n      next ← nodeToRemove.left\n    end if\n    if root = nodeToRemove\n      root = next\n    else if parent.left = nodeToRemove\n      parent.left = next\n    else if parent.right = nodeToRemove\n      parent.right = next\n    end if\n  end if\n  count ← count - 1\n  return true\nend remove\n```\n\n### Encontrar o Nó Pai\n\n```text\nfindParent(value, root)\n  Pre: value is the value of the node we want to find the parent of\n       root is the root node of the BST and is != ø\n  Post: a reference to the prent node of value if found; otherwise ø\n  if value = root.value\n    return ø\n  end if\n  if value < root.value\n    if root.left = ø\n      return ø\n    else if root.left.value = value\n      return root\n    else\n      return findParent(value, root.left)\n    end if\n  else\n    if root.right = ø\n      return ø\n    else if root.right.value = value\n      return root\n    else\n      return findParent(value, root.right)\n    end if\n  end if\nend findParent\n```\n\n### Encontrar um Nó\n\n```text\nfindNode(root, value)\n  Pre: value is the value of the node we want to find the parent of\n       root is the root node of the BST\n  Post: a reference to the node of value if found; otherwise ø\n  if root = ø\n    return ø\n  end if\n  if root.value = value\n    return root\n  else if value < root.value\n    return findNode(root.left, value)\n  else\n    return findNode(root.right, value)\n  end if\nend findNode\n```\n\n### Encontrar Mínimo\n\n```text\nfindMin(root)\n  Pre: root is the root node of the BST\n    root = ø\n  Post: the smallest value in the BST is located\n  if root.left = ø\n    return root.value\n  end if\n  findMin(root.left)\nend findMin\n```\n\n### Encontrar Máximo\n\n```text\nfindMax(root)\n  Pre: root is the root node of the BST\n    root = ø\n  Post: the largest value in the BST is located\n  if root.right = ø\n    return root.value\n  end if\n  findMax(root.right)\nend findMax\n```\n\n### Traversal\n\n#### Na Ordem Traversal (InOrder Traversal)\n\n```text\ninorder(root)\n  Pre: root is the root node of the BST\n  Post: the nodes in the BST have been visited in inorder\n  if root = ø\n    inorder(root.left)\n    yield root.value\n    inorder(root.right)\n  end if\nend inorder\n```\n\n#### Pré Ordem Traversal (PreOrder Traversal)\n\n```text\npreorder(root)\n  Pre: root is the root node of the BST\n  Post: the nodes in the BST have been visited in preorder\n  if root = ø\n    yield root.value\n    preorder(root.left)\n    preorder(root.right)\n  end if\nend preorder\n```\n\n#### Pós Ordem Traversal (PostOrder Traversal)\n\n```text\npostorder(root)\n  Pre: root is the root node of the BST\n  Post: the nodes in the BST have been visited in postorder\n  if root = ø\n    postorder(root.left)\n    postorder(root.right)\n    yield root.value\n  end if\nend postorder\n```\n\n## Complexidades\n\n### Complexidade de Tempo\n\n| Access    | Search    | Insertion | Deletion  |\n| :-------: | :-------: | :-------: | :-------: |\n| O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) |\n\n### Complexidade de Espaço\n\nO(n)\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_tree)\n- [Inserting to BST on YouTube](https://www.youtube.com/watch?v=wcIRPqTR3Kc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=9&t=0s)\n- [BST Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/BST.html)\n"
  },
  {
    "path": "src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js",
    "content": "import BinarySearchTree from '../BinarySearchTree';\n\ndescribe('BinarySearchTree', () => {\n  it('should create binary search tree', () => {\n    const bst = new BinarySearchTree();\n\n    expect(bst).toBeDefined();\n    expect(bst.root).toBeDefined();\n    expect(bst.root.value).toBeNull();\n    expect(bst.root.left).toBeNull();\n    expect(bst.root.right).toBeNull();\n  });\n\n  it('should insert values', () => {\n    const bst = new BinarySearchTree();\n\n    const insertedNode1 = bst.insert(10);\n    const insertedNode2 = bst.insert(20);\n    bst.insert(5);\n\n    expect(bst.toString()).toBe('5,10,20');\n    expect(insertedNode1.value).toBe(10);\n    expect(insertedNode2.value).toBe(20);\n  });\n\n  it('should check if value exists', () => {\n    const bst = new BinarySearchTree();\n\n    bst.insert(10);\n    bst.insert(20);\n    bst.insert(5);\n\n    expect(bst.contains(20)).toBe(true);\n    expect(bst.contains(40)).toBe(false);\n  });\n\n  it('should remove nodes', () => {\n    const bst = new BinarySearchTree();\n\n    bst.insert(10);\n    bst.insert(20);\n    bst.insert(5);\n\n    expect(bst.toString()).toBe('5,10,20');\n\n    const removed1 = bst.remove(5);\n    expect(bst.toString()).toBe('10,20');\n    expect(removed1).toBe(true);\n\n    const removed2 = bst.remove(20);\n    expect(bst.toString()).toBe('10');\n    expect(removed2).toBe(true);\n  });\n\n  it('should insert object values', () => {\n    const nodeValueCompareFunction = (a, b) => {\n      const normalizedA = a || { value: null };\n      const normalizedB = b || { value: null };\n\n      if (normalizedA.value === normalizedB.value) {\n        return 0;\n      }\n\n      return normalizedA.value < normalizedB.value ? -1 : 1;\n    };\n\n    const obj1 = { key: 'obj1', value: 1, toString: () => 'obj1' };\n    const obj2 = { key: 'obj2', value: 2, toString: () => 'obj2' };\n    const obj3 = { key: 'obj3', value: 3, toString: () => 'obj3' };\n\n    const bst = new BinarySearchTree(nodeValueCompareFunction);\n\n    bst.insert(obj2);\n    bst.insert(obj3);\n    bst.insert(obj1);\n\n    expect(bst.toString()).toBe('obj1,obj2,obj3');\n  });\n\n  it('should be traversed to sorted array', () => {\n    const bst = new BinarySearchTree();\n\n    bst.insert(10);\n    bst.insert(-10);\n    bst.insert(20);\n    bst.insert(-20);\n    bst.insert(25);\n    bst.insert(6);\n\n    expect(bst.toString()).toBe('-20,-10,6,10,20,25');\n    expect(bst.root.height).toBe(2);\n\n    bst.insert(4);\n\n    expect(bst.toString()).toBe('-20,-10,4,6,10,20,25');\n    expect(bst.root.height).toBe(3);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js",
    "content": "import BinarySearchTreeNode from '../BinarySearchTreeNode';\n\ndescribe('BinarySearchTreeNode', () => {\n  it('should create binary search tree', () => {\n    const bstNode = new BinarySearchTreeNode(2);\n\n    expect(bstNode.value).toBe(2);\n    expect(bstNode.left).toBeNull();\n    expect(bstNode.right).toBeNull();\n  });\n\n  it('should insert in itself if it is empty', () => {\n    const bstNode = new BinarySearchTreeNode();\n    bstNode.insert(1);\n\n    expect(bstNode.value).toBe(1);\n    expect(bstNode.left).toBeNull();\n    expect(bstNode.right).toBeNull();\n  });\n\n  it('should insert nodes in correct order', () => {\n    const bstNode = new BinarySearchTreeNode(2);\n    const insertedNode1 = bstNode.insert(1);\n\n    expect(insertedNode1.value).toBe(1);\n    expect(bstNode.toString()).toBe('1,2');\n    expect(bstNode.contains(1)).toBe(true);\n    expect(bstNode.contains(3)).toBe(false);\n\n    const insertedNode2 = bstNode.insert(3);\n\n    expect(insertedNode2.value).toBe(3);\n    expect(bstNode.toString()).toBe('1,2,3');\n    expect(bstNode.contains(3)).toBe(true);\n    expect(bstNode.contains(4)).toBe(false);\n\n    bstNode.insert(7);\n\n    expect(bstNode.toString()).toBe('1,2,3,7');\n    expect(bstNode.contains(7)).toBe(true);\n    expect(bstNode.contains(8)).toBe(false);\n\n    bstNode.insert(4);\n\n    expect(bstNode.toString()).toBe('1,2,3,4,7');\n    expect(bstNode.contains(4)).toBe(true);\n    expect(bstNode.contains(8)).toBe(false);\n\n    bstNode.insert(6);\n\n    expect(bstNode.toString()).toBe('1,2,3,4,6,7');\n    expect(bstNode.contains(6)).toBe(true);\n    expect(bstNode.contains(8)).toBe(false);\n  });\n\n  it('should not insert duplicates', () => {\n    const bstNode = new BinarySearchTreeNode(2);\n    bstNode.insert(1);\n\n    expect(bstNode.toString()).toBe('1,2');\n    expect(bstNode.contains(1)).toBe(true);\n    expect(bstNode.contains(3)).toBe(false);\n\n    bstNode.insert(1);\n\n    expect(bstNode.toString()).toBe('1,2');\n    expect(bstNode.contains(1)).toBe(true);\n    expect(bstNode.contains(3)).toBe(false);\n  });\n\n  it('should find min node', () => {\n    const node = new BinarySearchTreeNode(10);\n\n    node.insert(20);\n    node.insert(30);\n    node.insert(5);\n    node.insert(40);\n    node.insert(1);\n\n    expect(node.findMin()).not.toBeNull();\n    expect(node.findMin().value).toBe(1);\n  });\n\n  it('should be possible to attach meta information to binary search tree nodes', () => {\n    const node = new BinarySearchTreeNode(10);\n\n    node.insert(20);\n    const node1 = node.insert(30);\n    node.insert(5);\n    node.insert(40);\n    const node2 = node.insert(1);\n\n    node.meta.set('color', 'red');\n    node1.meta.set('color', 'black');\n    node2.meta.set('color', 'white');\n\n    expect(node.meta.get('color')).toBe('red');\n\n    expect(node.findMin()).not.toBeNull();\n    expect(node.findMin().value).toBe(1);\n    expect(node.findMin().meta.get('color')).toBe('white');\n    expect(node.find(30).meta.get('color')).toBe('black');\n  });\n\n  it('should find node', () => {\n    const node = new BinarySearchTreeNode(10);\n\n    node.insert(20);\n    node.insert(30);\n    node.insert(5);\n    node.insert(40);\n    node.insert(1);\n\n    expect(node.find(6)).toBeNull();\n    expect(node.find(5)).not.toBeNull();\n    expect(node.find(5).value).toBe(5);\n  });\n\n  it('should remove leaf nodes', () => {\n    const bstRootNode = new BinarySearchTreeNode();\n\n    bstRootNode.insert(10);\n    bstRootNode.insert(20);\n    bstRootNode.insert(5);\n\n    expect(bstRootNode.toString()).toBe('5,10,20');\n\n    const removed1 = bstRootNode.remove(5);\n    expect(bstRootNode.toString()).toBe('10,20');\n    expect(removed1).toBe(true);\n\n    const removed2 = bstRootNode.remove(20);\n    expect(bstRootNode.toString()).toBe('10');\n    expect(removed2).toBe(true);\n  });\n\n  it('should remove nodes with one child', () => {\n    const bstRootNode = new BinarySearchTreeNode();\n\n    bstRootNode.insert(10);\n    bstRootNode.insert(20);\n    bstRootNode.insert(5);\n    bstRootNode.insert(30);\n\n    expect(bstRootNode.toString()).toBe('5,10,20,30');\n\n    bstRootNode.remove(20);\n    expect(bstRootNode.toString()).toBe('5,10,30');\n\n    bstRootNode.insert(1);\n    expect(bstRootNode.toString()).toBe('1,5,10,30');\n\n    bstRootNode.remove(5);\n    expect(bstRootNode.toString()).toBe('1,10,30');\n  });\n\n  it('should remove nodes with two children', () => {\n    const bstRootNode = new BinarySearchTreeNode();\n\n    bstRootNode.insert(10);\n    bstRootNode.insert(20);\n    bstRootNode.insert(5);\n    bstRootNode.insert(30);\n    bstRootNode.insert(15);\n    bstRootNode.insert(25);\n\n    expect(bstRootNode.toString()).toBe('5,10,15,20,25,30');\n    expect(bstRootNode.find(20).left.value).toBe(15);\n    expect(bstRootNode.find(20).right.value).toBe(30);\n\n    bstRootNode.remove(20);\n    expect(bstRootNode.toString()).toBe('5,10,15,25,30');\n\n    bstRootNode.remove(15);\n    expect(bstRootNode.toString()).toBe('5,10,25,30');\n\n    bstRootNode.remove(10);\n    expect(bstRootNode.toString()).toBe('5,25,30');\n    expect(bstRootNode.value).toBe(25);\n\n    bstRootNode.remove(25);\n    expect(bstRootNode.toString()).toBe('5,30');\n\n    bstRootNode.remove(5);\n    expect(bstRootNode.toString()).toBe('30');\n  });\n\n  it('should remove node with no parent', () => {\n    const bstRootNode = new BinarySearchTreeNode();\n    expect(bstRootNode.toString()).toBe('');\n\n    bstRootNode.insert(1);\n    bstRootNode.insert(2);\n    expect(bstRootNode.toString()).toBe('1,2');\n\n    bstRootNode.remove(1);\n    expect(bstRootNode.toString()).toBe('2');\n\n    bstRootNode.remove(2);\n    expect(bstRootNode.toString()).toBe('');\n  });\n\n  it('should throw error when trying to remove not existing node', () => {\n    const bstRootNode = new BinarySearchTreeNode();\n\n    bstRootNode.insert(10);\n    bstRootNode.insert(20);\n\n    function removeNotExistingElementFromTree() {\n      bstRootNode.remove(30);\n    }\n\n    expect(removeNotExistingElementFromTree).toThrow();\n  });\n\n  it('should be possible to use objects as node values', () => {\n    const nodeValueComparatorCallback = (a, b) => {\n      const normalizedA = a || { value: null };\n      const normalizedB = b || { value: null };\n\n      if (normalizedA.value === normalizedB.value) {\n        return 0;\n      }\n\n      return normalizedA.value < normalizedB.value ? -1 : 1;\n    };\n\n    const obj1 = { key: 'obj1', value: 1, toString: () => 'obj1' };\n    const obj2 = { key: 'obj2', value: 2, toString: () => 'obj2' };\n    const obj3 = { key: 'obj3', value: 3, toString: () => 'obj3' };\n\n    const bstNode = new BinarySearchTreeNode(obj2, nodeValueComparatorCallback);\n    bstNode.insert(obj1);\n\n    expect(bstNode.toString()).toBe('obj1,obj2');\n    expect(bstNode.contains(obj1)).toBe(true);\n    expect(bstNode.contains(obj3)).toBe(false);\n\n    bstNode.insert(obj3);\n\n    expect(bstNode.toString()).toBe('obj1,obj2,obj3');\n    expect(bstNode.contains(obj3)).toBe(true);\n\n    expect(bstNode.findMin().value).toEqual(obj1);\n  });\n\n  it('should abandon removed node', () => {\n    const rootNode = new BinarySearchTreeNode('foo');\n    rootNode.insert('bar');\n    const childNode = rootNode.find('bar');\n    rootNode.remove('bar');\n\n    expect(childNode.parent).toBeNull();\n  });\n});\n"
  },
  {
    "path": "src/data-structures/tree/fenwick-tree/FenwickTree.js",
    "content": "export default class FenwickTree {\n  /**\n   * Constructor creates empty fenwick tree of size 'arraySize',\n   * however, array size is size+1, because index is 1-based.\n   *\n   * @param  {number} arraySize\n   */\n  constructor(arraySize) {\n    this.arraySize = arraySize;\n\n    // Fill tree array with zeros.\n    this.treeArray = Array(this.arraySize + 1).fill(0);\n  }\n\n  /**\n   * Adds value to existing value at position.\n   *\n   * @param  {number} position\n   * @param  {number} value\n   * @return {FenwickTree}\n   */\n  increase(position, value) {\n    if (position < 1 || position > this.arraySize) {\n      throw new Error('Position is out of allowed range');\n    }\n\n    for (let i = position; i <= this.arraySize; i += (i & -i)) {\n      this.treeArray[i] += value;\n    }\n\n    return this;\n  }\n\n  /**\n   * Query sum from index 1 to position.\n   *\n   * @param  {number} position\n   * @return {number}\n   */\n  query(position) {\n    if (position < 1 || position > this.arraySize) {\n      throw new Error('Position is out of allowed range');\n    }\n\n    let sum = 0;\n\n    for (let i = position; i > 0; i -= (i & -i)) {\n      sum += this.treeArray[i];\n    }\n\n    return sum;\n  }\n\n  /**\n   * Query sum from index leftIndex to rightIndex.\n   *\n   * @param  {number} leftIndex\n   * @param  {number} rightIndex\n   * @return {number}\n   */\n  queryRange(leftIndex, rightIndex) {\n    if (leftIndex > rightIndex) {\n      throw new Error('Left index can not be greater than right one');\n    }\n\n    if (leftIndex === 1) {\n      return this.query(rightIndex);\n    }\n\n    return this.query(rightIndex) - this.query(leftIndex - 1);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/tree/fenwick-tree/README.md",
    "content": "# Fenwick Tree / Binary Indexed Tree\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md) \n\nA **Fenwick tree** or **binary indexed tree** is a data \nstructure that can efficiently update elements and \ncalculate prefix sums in a table of numbers.\n\nWhen compared with a flat array of numbers, the Fenwick tree achieves a \nmuch better balance between two operations: element update and prefix sum \ncalculation. In a flat array of `n` numbers, you can either store the elements, \nor the prefix sums. In the first case, computing prefix sums requires linear \ntime; in the second case, updating the array elements requires linear time \n(in both cases, the other operation can be performed in constant time). \nFenwick trees allow both operations to be performed in `O(log n)` time. \nThis is achieved by representing the numbers as a tree, where the value of \neach node is the sum of the numbers in that subtree. The tree structure allows \noperations to be performed using only `O(log n)` node accesses.\n\n## Implementation Notes\n\nBinary Indexed Tree is represented as an array. Each node of Binary Indexed Tree \nstores sum of some elements of given array. Size of Binary Indexed Tree is equal \nto `n` where `n` is size of input array. In current implementation we have used \nsize as `n+1` for ease of implementation. All the indexes are 1-based.\n\n![Binary Indexed Tree](https://www.geeksforgeeks.org/wp-content/uploads/BITSum.png)\n\nOn the picture below you may see animated example of \ncreation of binary indexed tree for the \narray `[1, 2, 3, 4, 5]` by inserting one by one.\n\n![Fenwick Tree](https://upload.wikimedia.org/wikipedia/commons/d/dc/BITDemo.gif)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Fenwick_tree)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/)\n- [YouTube](https://www.youtube.com/watch?v=CWDQJGaN1gY&index=18&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/tree/fenwick-tree/README.pt-BR.md",
    "content": "# Árvore Fenwick / Árvore Binária Indexada (Fenwick Tree / Binary Indexed Tree)\n\nUma **árvore Fenwick** ou **árvore binária indexada** é um tipo de\nestrutura de dados que consegue eficiemente atualizar elementos e\ncalcular soma dos prefixos em uma tabela de números.\n\nQuando comparado com um _flat array_ de números, a árvore Fenwick\nalcança um balanceamento muito melhor entre duas operações: atualização\n(_update_) do elemento e cálculo da soma do prefíxo. Em uma _flar array_\nde `n` números, você pode tanto armazenar elementos quando a soma dos\nprefixos. Em ambos os casos, computar a soma dos prefixos requer ou \natualizar um array de elementos também requerem um tempo linear, contudo,\na demais operações podem ser realizadas com tempo constante.\nA árvore Fenwick permite ambas as operações serem realizadas com tempo\n`O(log n)`.\n\nIsto é possível devido a representação dos números como uma árvore, aonde\nos valores de cada nó é a soma dos números naquela sub-árvore. A estrutura\nde árvore permite operações a serem realizadas consumindo somente acessos\na nós em `O(log n)`.\n\n## Implementação de Nós\n\nÁrvore Binária Indexada é representada como um _array_. Em cada nó da Árvore\nBinária Indexada armazena a soma de alguns dos elementos de uma _array_\nfornecida. O tamanho da Árvore Binária Indexada é igual a `n` aonde `n` é o\ntamanho do _array_ de entrada. Na presente implementação nós utilizados o\ntamanho `n+1` para uma implementação fácil. Todos os índices são baseados em 1. \n\n![Binary Indexed Tree](https://www.geeksforgeeks.org/wp-content/uploads/BITSum.png)\n\nNa imagem abaixo você pode ver o exemplo animado da criação de uma árvore\nbinária indexada para o _array_ `[1, 2, 3, 4, 5]`, sendo inseridos um após\no outro.\n\n![Fenwick Tree](https://upload.wikimedia.org/wikipedia/commons/d/dc/BITDemo.gif)\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Fenwick_tree)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/)\n- [YouTube](https://www.youtube.com/watch?v=CWDQJGaN1gY&index=18&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n"
  },
  {
    "path": "src/data-structures/tree/fenwick-tree/__test__/FenwickTree.test.js",
    "content": "import FenwickTree from '../FenwickTree';\n\ndescribe('FenwickTree', () => {\n  it('should create empty fenwick tree of correct size', () => {\n    const tree1 = new FenwickTree(5);\n    expect(tree1.treeArray.length).toBe(5 + 1);\n\n    for (let i = 0; i < 5; i += 1) {\n      expect(tree1.treeArray[i]).toBe(0);\n    }\n\n    const tree2 = new FenwickTree(50);\n    expect(tree2.treeArray.length).toBe(50 + 1);\n  });\n\n  it('should create correct fenwick tree', () => {\n    const inputArray = [3, 2, -1, 6, 5, 4, -3, 3, 7, 2, 3];\n\n    const tree = new FenwickTree(inputArray.length);\n    expect(tree.treeArray.length).toBe(inputArray.length + 1);\n\n    inputArray.forEach((value, index) => {\n      tree.increase(index + 1, value);\n    });\n\n    expect(tree.treeArray).toEqual([0, 3, 5, -1, 10, 5, 9, -3, 19, 7, 9, 3]);\n\n    expect(tree.query(1)).toBe(3);\n    expect(tree.query(2)).toBe(5);\n    expect(tree.query(3)).toBe(4);\n    expect(tree.query(4)).toBe(10);\n    expect(tree.query(5)).toBe(15);\n    expect(tree.query(6)).toBe(19);\n    expect(tree.query(7)).toBe(16);\n    expect(tree.query(8)).toBe(19);\n    expect(tree.query(9)).toBe(26);\n    expect(tree.query(10)).toBe(28);\n    expect(tree.query(11)).toBe(31);\n\n    expect(tree.queryRange(1, 1)).toBe(3);\n    expect(tree.queryRange(1, 2)).toBe(5);\n    expect(tree.queryRange(2, 4)).toBe(7);\n    expect(tree.queryRange(6, 9)).toBe(11);\n\n    tree.increase(3, 1);\n\n    expect(tree.query(1)).toBe(3);\n    expect(tree.query(2)).toBe(5);\n    expect(tree.query(3)).toBe(5);\n    expect(tree.query(4)).toBe(11);\n    expect(tree.query(5)).toBe(16);\n    expect(tree.query(6)).toBe(20);\n    expect(tree.query(7)).toBe(17);\n    expect(tree.query(8)).toBe(20);\n    expect(tree.query(9)).toBe(27);\n    expect(tree.query(10)).toBe(29);\n    expect(tree.query(11)).toBe(32);\n\n    expect(tree.queryRange(1, 1)).toBe(3);\n    expect(tree.queryRange(1, 2)).toBe(5);\n    expect(tree.queryRange(2, 4)).toBe(8);\n    expect(tree.queryRange(6, 9)).toBe(11);\n  });\n\n  it('should correctly execute queries', () => {\n    const tree = new FenwickTree(5);\n\n    tree.increase(1, 4);\n    tree.increase(3, 7);\n\n    expect(tree.query(1)).toBe(4);\n    expect(tree.query(3)).toBe(11);\n    expect(tree.query(5)).toBe(11);\n    expect(tree.queryRange(2, 3)).toBe(7);\n\n    tree.increase(2, 5);\n    expect(tree.query(5)).toBe(16);\n\n    tree.increase(1, 3);\n    expect(tree.queryRange(1, 1)).toBe(7);\n    expect(tree.query(5)).toBe(19);\n    expect(tree.queryRange(1, 5)).toBe(19);\n  });\n\n  it('should throw exceptions', () => {\n    const tree = new FenwickTree(5);\n\n    const increaseAtInvalidLowIndex = () => {\n      tree.increase(0, 1);\n    };\n\n    const increaseAtInvalidHighIndex = () => {\n      tree.increase(10, 1);\n    };\n\n    const queryInvalidLowIndex = () => {\n      tree.query(0);\n    };\n\n    const queryInvalidHighIndex = () => {\n      tree.query(10);\n    };\n\n    const rangeQueryInvalidIndex = () => {\n      tree.queryRange(3, 2);\n    };\n\n    expect(increaseAtInvalidLowIndex).toThrow();\n    expect(increaseAtInvalidHighIndex).toThrow();\n    expect(queryInvalidLowIndex).toThrow();\n    expect(queryInvalidHighIndex).toThrow();\n    expect(rangeQueryInvalidIndex).toThrow();\n  });\n});\n"
  },
  {
    "path": "src/data-structures/tree/red-black-tree/README.md",
    "content": "# Red–Black Tree\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md) \n\nA **red–black tree** is a kind of self-balancing binary search \ntree in computer science. Each node of the binary tree has \nan extra bit, and that bit is often interpreted as the \ncolor (red or black) of the node. These color bits are used \nto ensure the tree remains approximately balanced during \ninsertions and deletions.\n\nBalance is preserved by painting each node of the tree with \none of two colors in a way that satisfies certain properties,\nwhich collectively constrain how unbalanced the tree can \nbecome in the worst case. When the tree is modified, the \nnew tree is subsequently rearranged and repainted to \nrestore the coloring properties. The properties are \ndesigned in such a way that this rearranging and recoloring \ncan be performed efficiently.\n\nThe balancing of the tree is not perfect, but it is good \nenough to allow it to guarantee searching in `O(log n)` time,\nwhere `n` is the total number of elements in the tree. \nThe insertion and deletion operations, along with the tree \nrearrangement and recoloring, are also performed \nin `O(log n)` time.\n\nAn example of a red–black tree:\n\n![red-black tree](https://upload.wikimedia.org/wikipedia/commons/6/66/Red-black_tree_example.svg)\n\n## Properties\n\nIn addition to the requirements imposed on a binary search \ntree the following must be satisfied by a red–black tree:\n\n- Each node is either red or black.\n- The root is black. This rule is sometimes omitted. \nSince the root can always be changed from red to black, \nbut not necessarily vice versa, this rule has little \neffect on analysis.\n- All leaves (NIL) are black.\n- If a node is red, then both its children are black.\n- Every path from a given node to any of its descendant \nNIL nodes contains the same number of black nodes.\n\nSome definitions: the number of black nodes from the root \nto a node is the node's **black depth**; the uniform \nnumber of black nodes in all paths from root to the leaves \nis called the **black-height** of the red–black tree.\n\nThese constraints enforce a critical property of red–black \ntrees: _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_. \nThe result is that the tree is roughly height-balanced. \nSince operations such as inserting, deleting, and finding \nvalues require worst-case time proportional to the height \nof the tree, this theoretical upper bound on the height \nallows red–black trees to be efficient in the worst case, \nunlike ordinary binary search trees.\n\n## Balancing during insertion\n\n### If uncle is RED\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase2.png)\n\n### If uncle is BLACK\n\n- Left Left Case (`p` is left child of `g` and `x` is left child of `p`)\n- Left Right Case (`p` is left child of `g` and `x` is right child of `p`)\n- Right Right Case (`p` is right child of `g` and `x` is right child of `p`)\n- Right Left Case (`p` is right child of `g` and `x` is left child of `p`)\n\n#### Left Left Case (See g, p and x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3a1.png)\n\n#### Left Right Case (See g, p and x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3b.png)\n\n#### Right Right Case (See g, p and x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3c.png)\n\n#### Right Left Case (See g, p and x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3d.png)\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree)\n- [Red Black Tree Insertion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=UaLIHuR1t8Q&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=63)\n- [Red Black Tree Deletion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=CTvfzU_uNKE&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=64)\n- [Red Black Tree Insertion on GeeksForGeeks](https://www.geeksforgeeks.org/red-black-tree-set-2-insert/)\n- [Red Black Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)\n"
  },
  {
    "path": "src/data-structures/tree/red-black-tree/README.pt-BR.md",
    "content": "# Árvore Vermelha-Preta (Red-Black Tree)\n\nUma **árvore vermelha-preta** é um tipo de árvore de pesquisa\nbinária auto balanceada na ciência da computação. Cada nó da \nárvore binária possui um _bit_ extra, e este _bit_ é frequentemente\ninterpretado com a cor (vermelho ou preto) do nó. Estas cores de _bits_\nsão utilizadas para garantir que a árvore permanece aproximadamente\nequilibrada durante as operações de inserções e remoções.\n\nO equilíbrio é preservado através da pintura de cada nó da árvore com\numa das duas cores, de maneira que satisfaça certas propriedades, das\nquais restringe nos piores dos casos, o quão desequilibrada a árvore\npode se tornar. Quando a árvore é modificada, a nova árvore é\nsubsequentemente reorganizada e repintada para restaurar as\npropriedades de coloração. As propriedades são designadas de tal modo que\nesta reorganização e nova pintura podem ser realizadas eficientemente.\n\nO balanceamento de uma árvore não é perfeito, mas é suficientemente bom\npara permitir e garantir uma pesquisa no tempo `O(log n)`, aonde `n` é o\nnúmero total de elementos na árvore.\nOperações de inserções e remoções, juntamente com a reorganização e \nrepintura da árvore, também são executados no tempo `O (log n)`.\n\nUm exemplo de uma árvore vermalha-preta:\n\n![red-black tree](https://upload.wikimedia.org/wikipedia/commons/6/66/Red-black_tree_example.svg)\n\n## Propriedades\n\nEm adição aos requerimentos impostos pela árvore de pesquisa binária,\nas seguintes condições devem ser satisfeitas pela árvore vermelha-preta:\n\n- Cada nó é tanto vermelho ou preto.\n- O nó raíz é preto. Esta regra algumas vezes é omitida.\nTendo em vista que a raíz pode sempre ser alterada de vermelho para preto,\nmas não de preto para vermelho, esta regra tem pouco efeito na análise.\n- Todas as folhas (Nulo/NIL) são pretas.\n- Caso um nó é vermelho, então seus filhos serão pretos.\n- Cada caminho de um determinado nó para qualquer um dos seus nós nulos (NIL)\ndescendentes contém o mesmo número de nós pretos.\n\nAlgumas definições: o número de nós pretos da raiz até um nó é a\n**profundidade preta**(_black depth_) do nó; o número uniforme de nós pretos\nem todos os caminhos da raíz até as folhas são chamados de **altura negra**\n(_black-height_) da árvore vermelha-preta.\n\nEssas restrições impõem uma propriedade crítica de árvores vermelhas e pretas:\n_o caminho da raiz até a folha mais distante não possui mais que o dobro do\ncomprimento do caminho da raiz até a folha mais próxima_.\nO resultado é que a árvore é grosseiramente balanceada na altura.\n\nTendo em vista que operações como inserções, remoção e pesquisa de valores\nrequerem nos piores dos casos um tempo proporcional a altura da ávore,\neste limite superior teórico na altura permite que as árvores vermelha-preta\nsejam eficientes no pior dos casos, ao contrário das árvores de busca binária\ncomuns.\n\n## Balanceamento durante a inserção\n\n### Se o tio é VERMELHO\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase2.png)\n\n### Se o tio é PRETO\n\n- Caso Esquerda Esquerda (`p` é o filho a esquerda de `g` e `x`, é o filho a esquerda de `p`)\n- Caso Esquerda Direita (`p` é o filho a esquerda de `g` e `x`, é o filho a direita de `p`)\n- Caso Direita Direita (`p` é o filho a direita de `g` e `x`, é o filho da direita de `p`)\n- Caso Direita Esqueda (`p` é o filho a direita de `g` e `x`, é o filho a esquerda de `p`)\n\n#### Caso Esquerda Esquerda (Veja g, p e x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3a1.png)\n\n#### Caso Esquerda Direita (Veja g, p e x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3b.png)\n\n#### Caso Direita Direita (Veja g, p e x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3c.png)\n\n#### Caso Direita Esquerda (Veja g, p e x)\n\n![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3d.png)\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree)\n- [Red Black Tree Insertion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=UaLIHuR1t8Q&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=63)\n- [Red Black Tree Deletion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=CTvfzU_uNKE&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=64)\n- [Red Black Tree Insertion on GeeksForGeeks](https://www.geeksforgeeks.org/red-black-tree-set-2-insert/)\n- [Red Black Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)\n"
  },
  {
    "path": "src/data-structures/tree/red-black-tree/RedBlackTree.js",
    "content": "import BinarySearchTree from '../binary-search-tree/BinarySearchTree';\n\n// Possible colors of red-black tree nodes.\nconst RED_BLACK_TREE_COLORS = {\n  red: 'red',\n  black: 'black',\n};\n\n// Color property name in meta information of the nodes.\nconst COLOR_PROP_NAME = 'color';\n\nexport default class RedBlackTree extends BinarySearchTree {\n  /**\n   * @param {*} value\n   * @return {BinarySearchTreeNode}\n   */\n  insert(value) {\n    const insertedNode = super.insert(value);\n\n    // if (!this.root.left && !this.root.right) {\n    if (this.nodeComparator.equal(insertedNode, this.root)) {\n      // Make root to always be black.\n      this.makeNodeBlack(insertedNode);\n    } else {\n      // Make all newly inserted nodes to be red.\n      this.makeNodeRed(insertedNode);\n    }\n\n    // Check all conditions and balance the node.\n    this.balance(insertedNode);\n\n    return insertedNode;\n  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  remove(value) {\n    throw new Error(`Can't remove ${value}. Remove method is not implemented yet`);\n  }\n\n  /**\n   * @param {BinarySearchTreeNode} node\n   */\n  balance(node) {\n    // If it is a root node then nothing to balance here.\n    if (this.nodeComparator.equal(node, this.root)) {\n      return;\n    }\n\n    // If the parent is black then done. Nothing to balance here.\n    if (this.isNodeBlack(node.parent)) {\n      return;\n    }\n\n    const grandParent = node.parent.parent;\n\n    if (node.uncle && this.isNodeRed(node.uncle)) {\n      // If node has red uncle then we need to do RECOLORING.\n\n      // Recolor parent and uncle to black.\n      this.makeNodeBlack(node.uncle);\n      this.makeNodeBlack(node.parent);\n\n      if (!this.nodeComparator.equal(grandParent, this.root)) {\n        // Recolor grand-parent to red if it is not root.\n        this.makeNodeRed(grandParent);\n      } else {\n        // If grand-parent is black root don't do anything.\n        // Since root already has two black sibling that we've just recolored.\n        return;\n      }\n\n      // Now do further checking for recolored grand-parent.\n      this.balance(grandParent);\n    } else if (!node.uncle || this.isNodeBlack(node.uncle)) {\n      // If node uncle is black or absent then we need to do ROTATIONS.\n\n      if (grandParent) {\n        // Grand parent that we will receive after rotations.\n        let newGrandParent;\n\n        if (this.nodeComparator.equal(grandParent.left, node.parent)) {\n          // Left case.\n          if (this.nodeComparator.equal(node.parent.left, node)) {\n            // Left-left case.\n            newGrandParent = this.leftLeftRotation(grandParent);\n          } else {\n            // Left-right case.\n            newGrandParent = this.leftRightRotation(grandParent);\n          }\n        } else {\n          // Right case.\n          if (this.nodeComparator.equal(node.parent.right, node)) {\n            // Right-right case.\n            newGrandParent = this.rightRightRotation(grandParent);\n          } else {\n            // Right-left case.\n            newGrandParent = this.rightLeftRotation(grandParent);\n          }\n        }\n\n        // Set newGrandParent as a root if it doesn't have parent.\n        if (newGrandParent && newGrandParent.parent === null) {\n          this.root = newGrandParent;\n\n          // Recolor root into black.\n          this.makeNodeBlack(this.root);\n        }\n\n        // Check if new grand parent don't violate red-black-tree rules.\n        this.balance(newGrandParent);\n      }\n    }\n  }\n\n  /**\n   * Left Left Case (p is left child of g and x is left child of p)\n   * @param {BinarySearchTreeNode|BinaryTreeNode} grandParentNode\n   * @return {BinarySearchTreeNode}\n   */\n  leftLeftRotation(grandParentNode) {\n    // Memorize the parent of grand-parent node.\n    const grandGrandParent = grandParentNode.parent;\n\n    // Check what type of sibling is our grandParentNode is (left or right).\n    let grandParentNodeIsLeft;\n    if (grandGrandParent) {\n      grandParentNodeIsLeft = this.nodeComparator.equal(grandGrandParent.left, grandParentNode);\n    }\n\n    // Memorize grandParentNode's left node.\n    const parentNode = grandParentNode.left;\n\n    // Memorize parent's right node since we're going to transfer it to\n    // grand parent's left subtree.\n    const parentRightNode = parentNode.right;\n\n    // Make grandParentNode to be right child of parentNode.\n    parentNode.setRight(grandParentNode);\n\n    // Move child's right subtree to grandParentNode's left subtree.\n    grandParentNode.setLeft(parentRightNode);\n\n    // Put parentNode node in place of grandParentNode.\n    if (grandGrandParent) {\n      if (grandParentNodeIsLeft) {\n        grandGrandParent.setLeft(parentNode);\n      } else {\n        grandGrandParent.setRight(parentNode);\n      }\n    } else {\n      // Make parent node a root\n      parentNode.parent = null;\n    }\n\n    // Swap colors of grandParentNode and parentNode.\n    this.swapNodeColors(parentNode, grandParentNode);\n\n    // Return new root node.\n    return parentNode;\n  }\n\n  /**\n   * Left Right Case (p is left child of g and x is right child of p)\n   * @param {BinarySearchTreeNode|BinaryTreeNode} grandParentNode\n   * @return {BinarySearchTreeNode}\n   */\n  leftRightRotation(grandParentNode) {\n    // Memorize left and left-right nodes.\n    const parentNode = grandParentNode.left;\n    const childNode = parentNode.right;\n\n    // We need to memorize child left node to prevent losing\n    // left child subtree. Later it will be re-assigned to\n    // parent's right sub-tree.\n    const childLeftNode = childNode.left;\n\n    // Make parentNode to be a left child of childNode node.\n    childNode.setLeft(parentNode);\n\n    // Move child's left subtree to parent's right subtree.\n    parentNode.setRight(childLeftNode);\n\n    // Put left-right node in place of left node.\n    grandParentNode.setLeft(childNode);\n\n    // Now we're ready to do left-left rotation.\n    return this.leftLeftRotation(grandParentNode);\n  }\n\n  /**\n   * Right Right Case (p is right child of g and x is right child of p)\n   * @param {BinarySearchTreeNode|BinaryTreeNode} grandParentNode\n   * @return {BinarySearchTreeNode}\n   */\n  rightRightRotation(grandParentNode) {\n    // Memorize the parent of grand-parent node.\n    const grandGrandParent = grandParentNode.parent;\n\n    // Check what type of sibling is our grandParentNode is (left or right).\n    let grandParentNodeIsLeft;\n    if (grandGrandParent) {\n      grandParentNodeIsLeft = this.nodeComparator.equal(grandGrandParent.left, grandParentNode);\n    }\n\n    // Memorize grandParentNode's right node.\n    const parentNode = grandParentNode.right;\n\n    // Memorize parent's left node since we're going to transfer it to\n    // grand parent's right subtree.\n    const parentLeftNode = parentNode.left;\n\n    // Make grandParentNode to be left child of parentNode.\n    parentNode.setLeft(grandParentNode);\n\n    // Transfer all left nodes from parent to right sub-tree of grandparent.\n    grandParentNode.setRight(parentLeftNode);\n\n    // Put parentNode node in place of grandParentNode.\n    if (grandGrandParent) {\n      if (grandParentNodeIsLeft) {\n        grandGrandParent.setLeft(parentNode);\n      } else {\n        grandGrandParent.setRight(parentNode);\n      }\n    } else {\n      // Make parent node a root.\n      parentNode.parent = null;\n    }\n\n    // Swap colors of granParent and parent nodes.\n    this.swapNodeColors(parentNode, grandParentNode);\n\n    // Return new root node.\n    return parentNode;\n  }\n\n  /**\n   * Right Left Case (p is right child of g and x is left child of p)\n   * @param {BinarySearchTreeNode|BinaryTreeNode} grandParentNode\n   * @return {BinarySearchTreeNode}\n   */\n  rightLeftRotation(grandParentNode) {\n    // Memorize right and right-left nodes.\n    const parentNode = grandParentNode.right;\n    const childNode = parentNode.left;\n\n    // We need to memorize child right node to prevent losing\n    // right child subtree. Later it will be re-assigned to\n    // parent's left sub-tree.\n    const childRightNode = childNode.right;\n\n    // Make parentNode to be a right child of childNode.\n    childNode.setRight(parentNode);\n\n    // Move child's right subtree to parent's left subtree.\n    parentNode.setLeft(childRightNode);\n\n    // Put childNode node in place of parentNode.\n    grandParentNode.setRight(childNode);\n\n    // Now we're ready to do right-right rotation.\n    return this.rightRightRotation(grandParentNode);\n  }\n\n  /**\n   * @param {BinarySearchTreeNode|BinaryTreeNode} node\n   * @return {BinarySearchTreeNode}\n   */\n  makeNodeRed(node) {\n    node.meta.set(COLOR_PROP_NAME, RED_BLACK_TREE_COLORS.red);\n\n    return node;\n  }\n\n  /**\n   * @param {BinarySearchTreeNode|BinaryTreeNode} node\n   * @return {BinarySearchTreeNode}\n   */\n  makeNodeBlack(node) {\n    node.meta.set(COLOR_PROP_NAME, RED_BLACK_TREE_COLORS.black);\n\n    return node;\n  }\n\n  /**\n   * @param {BinarySearchTreeNode|BinaryTreeNode} node\n   * @return {boolean}\n   */\n  isNodeRed(node) {\n    return node.meta.get(COLOR_PROP_NAME) === RED_BLACK_TREE_COLORS.red;\n  }\n\n  /**\n   * @param {BinarySearchTreeNode|BinaryTreeNode} node\n   * @return {boolean}\n   */\n  isNodeBlack(node) {\n    return node.meta.get(COLOR_PROP_NAME) === RED_BLACK_TREE_COLORS.black;\n  }\n\n  /**\n   * @param {BinarySearchTreeNode|BinaryTreeNode} node\n   * @return {boolean}\n   */\n  isNodeColored(node) {\n    return this.isNodeRed(node) || this.isNodeBlack(node);\n  }\n\n  /**\n   * @param {BinarySearchTreeNode|BinaryTreeNode} firstNode\n   * @param {BinarySearchTreeNode|BinaryTreeNode} secondNode\n   */\n  swapNodeColors(firstNode, secondNode) {\n    const firstColor = firstNode.meta.get(COLOR_PROP_NAME);\n    const secondColor = secondNode.meta.get(COLOR_PROP_NAME);\n\n    firstNode.meta.set(COLOR_PROP_NAME, secondColor);\n    secondNode.meta.set(COLOR_PROP_NAME, firstColor);\n  }\n}\n"
  },
  {
    "path": "src/data-structures/tree/red-black-tree/__test__/RedBlackTree.test.js",
    "content": "import RedBlackTree from '../RedBlackTree';\n\ndescribe('RedBlackTree', () => {\n  it('should always color first inserted node as black', () => {\n    const tree = new RedBlackTree();\n\n    const firstInsertedNode = tree.insert(10);\n\n    expect(tree.isNodeColored(firstInsertedNode)).toBe(true);\n    expect(tree.isNodeBlack(firstInsertedNode)).toBe(true);\n    expect(tree.isNodeRed(firstInsertedNode)).toBe(false);\n\n    expect(tree.toString()).toBe('10');\n    expect(tree.root.height).toBe(0);\n  });\n\n  it('should always color new leaf node as red', () => {\n    const tree = new RedBlackTree();\n\n    const firstInsertedNode = tree.insert(10);\n    const secondInsertedNode = tree.insert(15);\n    const thirdInsertedNode = tree.insert(5);\n\n    expect(tree.isNodeBlack(firstInsertedNode)).toBe(true);\n    expect(tree.isNodeRed(secondInsertedNode)).toBe(true);\n    expect(tree.isNodeRed(thirdInsertedNode)).toBe(true);\n\n    expect(tree.toString()).toBe('5,10,15');\n    expect(tree.root.height).toBe(1);\n  });\n\n  it('should balance itself', () => {\n    const tree = new RedBlackTree();\n\n    tree.insert(5);\n    tree.insert(10);\n    tree.insert(15);\n    tree.insert(20);\n    tree.insert(25);\n    tree.insert(30);\n\n    expect(tree.toString()).toBe('5,10,15,20,25,30');\n    expect(tree.root.height).toBe(3);\n  });\n\n  it('should balance itself when parent is black', () => {\n    const tree = new RedBlackTree();\n\n    const node1 = tree.insert(10);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n\n    const node2 = tree.insert(-10);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeRed(node2)).toBe(true);\n\n    const node3 = tree.insert(20);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeRed(node2)).toBe(true);\n    expect(tree.isNodeRed(node3)).toBe(true);\n\n    const node4 = tree.insert(-20);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n\n    const node5 = tree.insert(25);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n\n    const node6 = tree.insert(6);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n    expect(tree.isNodeRed(node6)).toBe(true);\n\n    expect(tree.toString()).toBe('-20,-10,6,10,20,25');\n    expect(tree.root.height).toBe(2);\n\n    const node7 = tree.insert(4);\n\n    expect(tree.root.left.value).toEqual(node2.value);\n\n    expect(tree.toString()).toBe('-20,-10,4,6,10,20,25');\n    expect(tree.root.height).toBe(3);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeRed(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeBlack(node4)).toBe(true);\n    expect(tree.isNodeBlack(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n    expect(tree.isNodeBlack(node6)).toBe(true);\n    expect(tree.isNodeRed(node7)).toBe(true);\n  });\n\n  it('should balance itself when uncle is red', () => {\n    const tree = new RedBlackTree();\n\n    const node1 = tree.insert(10);\n    const node2 = tree.insert(-10);\n    const node3 = tree.insert(20);\n    const node4 = tree.insert(-20);\n    const node5 = tree.insert(6);\n    const node6 = tree.insert(15);\n    const node7 = tree.insert(25);\n    const node8 = tree.insert(2);\n    const node9 = tree.insert(8);\n\n    expect(tree.toString()).toBe('-20,-10,2,6,8,10,15,20,25');\n    expect(tree.root.height).toBe(3);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeRed(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeBlack(node4)).toBe(true);\n    expect(tree.isNodeBlack(node5)).toBe(true);\n    expect(tree.isNodeRed(node6)).toBe(true);\n    expect(tree.isNodeRed(node7)).toBe(true);\n    expect(tree.isNodeRed(node8)).toBe(true);\n    expect(tree.isNodeRed(node9)).toBe(true);\n\n    const node10 = tree.insert(4);\n\n    expect(tree.toString()).toBe('-20,-10,2,4,6,8,10,15,20,25');\n    expect(tree.root.height).toBe(3);\n\n    expect(tree.root.value).toBe(node5.value);\n\n    expect(tree.isNodeBlack(node5)).toBe(true);\n    expect(tree.isNodeRed(node1)).toBe(true);\n    expect(tree.isNodeRed(node2)).toBe(true);\n    expect(tree.isNodeRed(node10)).toBe(true);\n    expect(tree.isNodeRed(node6)).toBe(true);\n    expect(tree.isNodeRed(node7)).toBe(true);\n    expect(tree.isNodeBlack(node4)).toBe(true);\n    expect(tree.isNodeBlack(node8)).toBe(true);\n    expect(tree.isNodeBlack(node9)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n  });\n\n  it('should do left-left rotation', () => {\n    const tree = new RedBlackTree();\n\n    const node1 = tree.insert(10);\n    const node2 = tree.insert(-10);\n    const node3 = tree.insert(20);\n    const node4 = tree.insert(7);\n    const node5 = tree.insert(15);\n\n    expect(tree.toString()).toBe('-10,7,10,15,20');\n    expect(tree.root.height).toBe(2);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n\n    const node6 = tree.insert(13);\n\n    expect(tree.toString()).toBe('-10,7,10,13,15,20');\n    expect(tree.root.height).toBe(2);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node5)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node6)).toBe(true);\n    expect(tree.isNodeRed(node3)).toBe(true);\n  });\n\n  it('should do left-right rotation', () => {\n    const tree = new RedBlackTree();\n\n    const node1 = tree.insert(10);\n    const node2 = tree.insert(-10);\n    const node3 = tree.insert(20);\n    const node4 = tree.insert(7);\n    const node5 = tree.insert(15);\n\n    expect(tree.toString()).toBe('-10,7,10,15,20');\n    expect(tree.root.height).toBe(2);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n\n    const node6 = tree.insert(17);\n\n    expect(tree.toString()).toBe('-10,7,10,15,17,20');\n    expect(tree.root.height).toBe(2);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node6)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n    expect(tree.isNodeRed(node3)).toBe(true);\n  });\n\n  it('should do recoloring, left-left and left-right rotation', () => {\n    const tree = new RedBlackTree();\n\n    const node1 = tree.insert(10);\n    const node2 = tree.insert(-10);\n    const node3 = tree.insert(20);\n    const node4 = tree.insert(-20);\n    const node5 = tree.insert(6);\n    const node6 = tree.insert(15);\n    const node7 = tree.insert(30);\n    const node8 = tree.insert(1);\n    const node9 = tree.insert(9);\n\n    expect(tree.toString()).toBe('-20,-10,1,6,9,10,15,20,30');\n    expect(tree.root.height).toBe(3);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeRed(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeBlack(node4)).toBe(true);\n    expect(tree.isNodeBlack(node5)).toBe(true);\n    expect(tree.isNodeRed(node6)).toBe(true);\n    expect(tree.isNodeRed(node7)).toBe(true);\n    expect(tree.isNodeRed(node8)).toBe(true);\n    expect(tree.isNodeRed(node9)).toBe(true);\n\n    tree.insert(4);\n\n    expect(tree.toString()).toBe('-20,-10,1,4,6,9,10,15,20,30');\n    expect(tree.root.height).toBe(3);\n  });\n\n  it('should do right-left rotation', () => {\n    const tree = new RedBlackTree();\n\n    const node1 = tree.insert(10);\n    const node2 = tree.insert(-10);\n    const node3 = tree.insert(20);\n    const node4 = tree.insert(-20);\n    const node5 = tree.insert(6);\n    const node6 = tree.insert(30);\n\n    expect(tree.toString()).toBe('-20,-10,6,10,20,30');\n    expect(tree.root.height).toBe(2);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node3)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n    expect(tree.isNodeRed(node6)).toBe(true);\n\n    const node7 = tree.insert(25);\n\n    const rightNode = tree.root.right;\n    const rightLeftNode = rightNode.left;\n    const rightRightNode = rightNode.right;\n\n    expect(rightNode.value).toBe(node7.value);\n    expect(rightLeftNode.value).toBe(node3.value);\n    expect(rightRightNode.value).toBe(node6.value);\n\n    expect(tree.toString()).toBe('-20,-10,6,10,20,25,30');\n    expect(tree.root.height).toBe(2);\n\n    expect(tree.isNodeBlack(node1)).toBe(true);\n    expect(tree.isNodeBlack(node2)).toBe(true);\n    expect(tree.isNodeBlack(node7)).toBe(true);\n    expect(tree.isNodeRed(node4)).toBe(true);\n    expect(tree.isNodeRed(node5)).toBe(true);\n    expect(tree.isNodeRed(node3)).toBe(true);\n    expect(tree.isNodeRed(node6)).toBe(true);\n  });\n\n  it('should do left-left rotation with left grand-parent', () => {\n    const tree = new RedBlackTree();\n\n    tree.insert(20);\n    tree.insert(15);\n    tree.insert(25);\n    tree.insert(10);\n    tree.insert(5);\n\n    expect(tree.toString()).toBe('5,10,15,20,25');\n    expect(tree.root.height).toBe(2);\n  });\n\n  it('should do right-right rotation with left grand-parent', () => {\n    const tree = new RedBlackTree();\n\n    tree.insert(20);\n    tree.insert(15);\n    tree.insert(25);\n    tree.insert(17);\n    tree.insert(19);\n\n    expect(tree.toString()).toBe('15,17,19,20,25');\n    expect(tree.root.height).toBe(2);\n  });\n\n  it('should throw an error when trying to remove node', () => {\n    const removeNodeFromRedBlackTree = () => {\n      const tree = new RedBlackTree();\n\n      tree.remove(1);\n    };\n\n    expect(removeNodeFromRedBlackTree).toThrow();\n  });\n});\n"
  },
  {
    "path": "src/data-structures/tree/segment-tree/README.md",
    "content": "# Segment Tree\n\n_Read this in other languages:_\n[_Português_](README.pt-BR.md) \n\nIn computer science, a **segment tree** also known as a statistic tree \nis a tree data structure used for storing information about intervals, \nor segments. It allows querying which of the stored segments contain \na given point. It is, in principle, a static structure; that is, \nit's a structure that cannot be modified once it's built. A similar \ndata structure is the interval tree.\n\nA segment tree is a binary tree. The root of the tree represents the \nwhole array. The two children of the root represent the \nfirst and second halves of the array. Similarly, the \nchildren of each node corresponds to the two halves of \nthe array corresponding to the node.\n\nWe build the tree bottom up, with the value of each node \nbeing the \"minimum\" (or any other function) of its children's values. This will \ntake `O(n log n)` time. The number \nof operations done is the height of the tree, which \nis `O(log n)`. To do range queries, each node splits the \nquery into two parts, one sub-query for each child. \nIf a query contains the whole subarray of a node, we \ncan use the precomputed value at the node. Using this \noptimisation, we can prove that only `O(log n)` minimum \noperations are done.\n\n![Min Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/RangeMinimumQuery.png)\n\n![Sum Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/segment-tree1.png)\n\n## Application\n\nA segment tree is a data structure designed to perform \ncertain array operations efficiently - especially those \ninvolving range queries.\n\nApplications of the segment tree are in the areas of computational geometry, \nand geographic information systems.\n\nCurrent implementation of Segment Tree implies that you may\npass any binary (with two input params) function to it and \nthus you're able to do range query for variety of functions.\nIn tests you may find examples of doing `min`, `max` and `sum` range\nqueries on SegmentTree.\n \n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Segment_tree)\n- [YouTube](https://www.youtube.com/watch?v=ZBHKZF5w4YU&index=65&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/)\n"
  },
  {
    "path": "src/data-structures/tree/segment-tree/README.pt-BR.md",
    "content": "# Árvore de Segmento (Segment Tree)\n\nNa ciência da computação, uma **árvore de segmento** também conhecida como\nárvore estatística é uma árvore de estrutura de dados utilizadas para\narmazenar informações sobre intervalores ou segmentos. Ela permite pesquisas\nno qual os segmentos armazenados contém um ponto fornecido. Isto é,\nem princípio, uma estrutura estática; ou seja, é uma estrutura que não pode\nser modificada depois de inicializada. Uma estrutura de dados similar é a\nárvore de intervalos.\n\nUma árvore de segmento é uma árvore binária. A raíz da árvore representa a\n_array_ inteira. Os dois filhos da raíz representam a primeira e a segunda\nmetade da _array_. Similarmente, os filhos de cada nó correspondem ao número\ndas duas metadas da _array_ correspondente do nó.\n\nNós construímos a árvore debaixo para cima, com o valor de cada nó sendo o \n\"mínimo\" (ou qualquer outra função) dos valores de seus filhos. Isto consumirá\ntempo `O(n log n)`. O número de oprações realizadas é equivalente a altura da\nárvore, pela qual consome tempo `O(log n)`. Para fazer consultas de intervalos,\ncada nó divide a consulta em duas partes, sendo uma sub consulta para cada filho.\nSe uma pesquisa contém todo o _subarray_ de um nó, nós podemos utilizar do valor\npré-calculado do nó. Utilizando esta otimização, nós podemos provar que somente\noperações mínimas `O(log n)` são realizadas.\n\n![Min Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/RangeMinimumQuery.png)\n\n![Sum Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/segment-tree1.png)\n\n## Aplicação\n\nUma árvore de segmento é uma estrutura de dados designada a realizar\ncertas operações de _array_ eficientemente, especialmente aquelas envolvendo\nconsultas de intervalos.\n\nAplicações da árvore de segmentos são nas áreas de computação geométrica e\nsistemas de informação geográficos.\n\nA implementação atual da Árvore de Segmentos implica que você pode passar\nqualquer função binária (com dois parâmetros de entradas) e então, você\nserá capaz de realizar consultas de intervalos para uma variedade de funções.\nNos testes você poderá encontrar exemplos realizando `min`, `max` e consultas de\nintervalo `sum` na árvore segmentada (SegmentTree).\n \n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Segment_tree)\n- [YouTube](https://www.youtube.com/watch?v=ZBHKZF5w4YU&index=65&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)\n- [GeeksForGeeks](https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/)\n"
  },
  {
    "path": "src/data-structures/tree/segment-tree/SegmentTree.js",
    "content": "import isPowerOfTwo from '../../../algorithms/math/is-power-of-two/isPowerOfTwo';\n\nexport default class SegmentTree {\n  /**\n   * @param {number[]} inputArray\n   * @param {function} operation - binary function (i.e. sum, min)\n   * @param {number} operationFallback - operation fallback value (i.e. 0 for sum, Infinity for min)\n   */\n  constructor(inputArray, operation, operationFallback) {\n    this.inputArray = inputArray;\n    this.operation = operation;\n    this.operationFallback = operationFallback;\n\n    // Init array representation of segment tree.\n    this.segmentTree = this.initSegmentTree(this.inputArray);\n\n    this.buildSegmentTree();\n  }\n\n  /**\n   * @param {number[]} inputArray\n   * @return {number[]}\n   */\n  initSegmentTree(inputArray) {\n    let segmentTreeArrayLength;\n    const inputArrayLength = inputArray.length;\n\n    if (isPowerOfTwo(inputArrayLength)) {\n      // If original array length is a power of two.\n      segmentTreeArrayLength = (2 * inputArrayLength) - 1;\n    } else {\n      // If original array length is not a power of two then we need to find\n      // next number that is a power of two and use it to calculate\n      // tree array size. This is happens because we need to fill empty children\n      // in perfect binary tree with nulls.And those nulls need extra space.\n      const currentPower = Math.floor(Math.log2(inputArrayLength));\n      const nextPower = currentPower + 1;\n      const nextPowerOfTwoNumber = 2 ** nextPower;\n      segmentTreeArrayLength = (2 * nextPowerOfTwoNumber) - 1;\n    }\n\n    return new Array(segmentTreeArrayLength).fill(null);\n  }\n\n  /**\n   * Build segment tree.\n   */\n  buildSegmentTree() {\n    const leftIndex = 0;\n    const rightIndex = this.inputArray.length - 1;\n    const position = 0;\n    this.buildTreeRecursively(leftIndex, rightIndex, position);\n  }\n\n  /**\n   * Build segment tree recursively.\n   *\n   * @param {number} leftInputIndex\n   * @param {number} rightInputIndex\n   * @param {number} position\n   */\n  buildTreeRecursively(leftInputIndex, rightInputIndex, position) {\n    // If low input index and high input index are equal that would mean\n    // the we have finished splitting and we are already came to the leaf\n    // of the segment tree. We need to copy this leaf value from input\n    // array to segment tree.\n    if (leftInputIndex === rightInputIndex) {\n      this.segmentTree[position] = this.inputArray[leftInputIndex];\n      return;\n    }\n\n    // Split input array on two halves and process them recursively.\n    const middleIndex = Math.floor((leftInputIndex + rightInputIndex) / 2);\n    // Process left half of the input array.\n    this.buildTreeRecursively(leftInputIndex, middleIndex, this.getLeftChildIndex(position));\n    // Process right half of the input array.\n    this.buildTreeRecursively(middleIndex + 1, rightInputIndex, this.getRightChildIndex(position));\n\n    // Once every tree leaf is not empty we're able to build tree bottom up using\n    // provided operation function.\n    this.segmentTree[position] = this.operation(\n      this.segmentTree[this.getLeftChildIndex(position)],\n      this.segmentTree[this.getRightChildIndex(position)],\n    );\n  }\n\n  /**\n   * Do range query on segment tree in context of this.operation function.\n   *\n   * @param {number} queryLeftIndex\n   * @param {number} queryRightIndex\n   * @return {number}\n   */\n  rangeQuery(queryLeftIndex, queryRightIndex) {\n    const leftIndex = 0;\n    const rightIndex = this.inputArray.length - 1;\n    const position = 0;\n\n    return this.rangeQueryRecursive(\n      queryLeftIndex,\n      queryRightIndex,\n      leftIndex,\n      rightIndex,\n      position,\n    );\n  }\n\n  /**\n   * Do range query on segment tree recursively in context of this.operation function.\n   *\n   * @param {number} queryLeftIndex - left index of the query\n   * @param {number} queryRightIndex - right index of the query\n   * @param {number} leftIndex - left index of input array segment\n   * @param {number} rightIndex - right index of input array segment\n   * @param {number} position - root position in binary tree\n   * @return {number}\n   */\n  rangeQueryRecursive(queryLeftIndex, queryRightIndex, leftIndex, rightIndex, position) {\n    if (queryLeftIndex <= leftIndex && queryRightIndex >= rightIndex) {\n      // Total overlap.\n      return this.segmentTree[position];\n    }\n\n    if (queryLeftIndex > rightIndex || queryRightIndex < leftIndex) {\n      // No overlap.\n      return this.operationFallback;\n    }\n\n    // Partial overlap.\n    const middleIndex = Math.floor((leftIndex + rightIndex) / 2);\n\n    const leftOperationResult = this.rangeQueryRecursive(\n      queryLeftIndex,\n      queryRightIndex,\n      leftIndex,\n      middleIndex,\n      this.getLeftChildIndex(position),\n    );\n\n    const rightOperationResult = this.rangeQueryRecursive(\n      queryLeftIndex,\n      queryRightIndex,\n      middleIndex + 1,\n      rightIndex,\n      this.getRightChildIndex(position),\n    );\n\n    return this.operation(leftOperationResult, rightOperationResult);\n  }\n\n  /**\n   * Left child index.\n   * @param {number} parentIndex\n   * @return {number}\n   */\n  getLeftChildIndex(parentIndex) {\n    return (2 * parentIndex) + 1;\n  }\n\n  /**\n   * Right child index.\n   * @param {number} parentIndex\n   * @return {number}\n   */\n  getRightChildIndex(parentIndex) {\n    return (2 * parentIndex) + 2;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/tree/segment-tree/__test__/SegmentTree.test.js",
    "content": "import SegmentTree from '../SegmentTree';\n\ndescribe('SegmentTree', () => {\n  it('should build tree for input array #0 with length of power of two', () => {\n    const array = [-1, 2];\n    const segmentTree = new SegmentTree(array, Math.min, Infinity);\n\n    expect(segmentTree.segmentTree).toEqual([-1, -1, 2]);\n    expect(segmentTree.segmentTree.length).toBe((2 * array.length) - 1);\n  });\n\n  it('should build tree for input array #1 with length of power of two', () => {\n    const array = [-1, 2, 4, 0];\n    const segmentTree = new SegmentTree(array, Math.min, Infinity);\n\n    expect(segmentTree.segmentTree).toEqual([-1, -1, 0, -1, 2, 4, 0]);\n    expect(segmentTree.segmentTree.length).toBe((2 * array.length) - 1);\n  });\n\n  it('should build tree for input array #0 with length not of power of two', () => {\n    const array = [0, 1, 2];\n    const segmentTree = new SegmentTree(array, Math.min, Infinity);\n\n    expect(segmentTree.segmentTree).toEqual([0, 0, 2, 0, 1, null, null]);\n    expect(segmentTree.segmentTree.length).toBe((2 * 4) - 1);\n  });\n\n  it('should build tree for input array #1 with length not of power of two', () => {\n    const array = [-1, 3, 4, 0, 2, 1];\n    const segmentTree = new SegmentTree(array, Math.min, Infinity);\n\n    expect(segmentTree.segmentTree).toEqual([\n      -1, -1, 0, -1, 4, 0, 1, -1, 3, null, null, 0, 2, null, null,\n    ]);\n    expect(segmentTree.segmentTree.length).toBe((2 * 8) - 1);\n  });\n\n  it('should build max array', () => {\n    const array = [-1, 2, 4, 0];\n    const segmentTree = new SegmentTree(array, Math.max, -Infinity);\n\n    expect(segmentTree.segmentTree).toEqual([4, 2, 4, -1, 2, 4, 0]);\n    expect(segmentTree.segmentTree.length).toBe((2 * array.length) - 1);\n  });\n\n  it('should build sum array', () => {\n    const array = [-1, 2, 4, 0];\n    const segmentTree = new SegmentTree(array, (a, b) => (a + b), 0);\n\n    expect(segmentTree.segmentTree).toEqual([5, 1, 4, -1, 2, 4, 0]);\n    expect(segmentTree.segmentTree.length).toBe((2 * array.length) - 1);\n  });\n\n  it('should do min range query on power of two length array', () => {\n    const array = [-1, 3, 4, 0, 2, 1];\n    const segmentTree = new SegmentTree(array, Math.min, Infinity);\n\n    expect(segmentTree.rangeQuery(0, 5)).toBe(-1);\n    expect(segmentTree.rangeQuery(0, 2)).toBe(-1);\n    expect(segmentTree.rangeQuery(1, 3)).toBe(0);\n    expect(segmentTree.rangeQuery(2, 4)).toBe(0);\n    expect(segmentTree.rangeQuery(4, 5)).toBe(1);\n    expect(segmentTree.rangeQuery(2, 2)).toBe(4);\n  });\n\n  it('should do min range query on not power of two length array', () => {\n    const array = [-1, 2, 4, 0];\n    const segmentTree = new SegmentTree(array, Math.min, Infinity);\n\n    expect(segmentTree.rangeQuery(0, 4)).toBe(-1);\n    expect(segmentTree.rangeQuery(0, 1)).toBe(-1);\n    expect(segmentTree.rangeQuery(1, 3)).toBe(0);\n    expect(segmentTree.rangeQuery(1, 2)).toBe(2);\n    expect(segmentTree.rangeQuery(2, 3)).toBe(0);\n    expect(segmentTree.rangeQuery(2, 2)).toBe(4);\n  });\n\n  it('should do max range query', () => {\n    const array = [-1, 3, 4, 0, 2, 1];\n    const segmentTree = new SegmentTree(array, Math.max, -Infinity);\n\n    expect(segmentTree.rangeQuery(0, 5)).toBe(4);\n    expect(segmentTree.rangeQuery(0, 1)).toBe(3);\n    expect(segmentTree.rangeQuery(1, 3)).toBe(4);\n    expect(segmentTree.rangeQuery(2, 4)).toBe(4);\n    expect(segmentTree.rangeQuery(4, 5)).toBe(2);\n    expect(segmentTree.rangeQuery(3, 3)).toBe(0);\n  });\n\n  it('should do sum range query', () => {\n    const array = [-1, 3, 4, 0, 2, 1];\n    const segmentTree = new SegmentTree(array, (a, b) => (a + b), 0);\n\n    expect(segmentTree.rangeQuery(0, 5)).toBe(9);\n    expect(segmentTree.rangeQuery(0, 1)).toBe(2);\n    expect(segmentTree.rangeQuery(1, 3)).toBe(7);\n    expect(segmentTree.rangeQuery(2, 4)).toBe(6);\n    expect(segmentTree.rangeQuery(4, 5)).toBe(3);\n    expect(segmentTree.rangeQuery(3, 3)).toBe(0);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/trie/README.ko-KO.md",
    "content": "# Trie\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_Português_](README.pt-BR.md),\n[_Українська_](README.uk-UA.md),\n[_한국어_](README.ko-KO.md)\n\n컴퓨터 과학에서 **트라이**는 디지털 트리라고도 불리며 때로는 기수 트리 또는 접두사 트리(접두사로 검색할 수 있기 때문에)라고도 불리며 일종의 검색 트리입니다. 키가 보통 문자열인 동적 집합 또는 연관 배열을 저장하는 데 사용되는 순서가 지정된 트리 데이터 구조입니다. 이진 검색 트리와 달리 트리의 어떤 노드도 해당 노드와 연결된 키를 저장하지 않으며 대신 트리의 위치가 해당 노드와 연결된 키를 정의합니다. 노드의 모든 하위 항목은 해당 노드와 연결된 문자열의 공통 접두사를 가지며 루트는 빈 문자열과 연결됩니다. 값은 모든 노드와 반드시 연결되지는 않습니다. 오히려 값은 나뭇잎과 관심 있는 키에 해당하는 일부 내부 노드에만 연결되는 경향이 있습니다. 접두사 트리의 공간에 최적화된 표현은 콤팩트 접두사 트리를 참조하십시오.\n\n![Trie](./images/trie.jpg)\n\n_Made with [okso.app](https://okso.app)_\n\n## 참조\n\n- [Wikipedia](<https://ko.wikipedia.org/wiki/%ED%8A%B8%EB%9D%BC%EC%9D%B4_(%EC%BB%B4%ED%93%A8%ED%8C%85)>)\n- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)\n"
  },
  {
    "path": "src/data-structures/trie/README.md",
    "content": "# Trie\n\n_Read this in other languages:_\n[_简体中文_](README.zh-CN.md),\n[_Русский_](README.ru-RU.md),\n[_Português_](README.pt-BR.md),\n[_Українська_](README.uk-UA.md),\n[_한국어_](README.ko-KO.md)\n\nIn computer science, a **trie**, also called digital tree and sometimes\nradix tree or prefix tree (as they can be searched by prefixes),\nis a kind of search tree—an ordered tree data structure that is\nused to store a dynamic set or associative array where the keys\nare usually strings. Unlike a binary search tree, no node in the\ntree stores the key associated with that node; instead, its\nposition in the tree defines the key with which it is associated.\nAll the descendants of a node have a common prefix of the string\nassociated with that node, and the root is associated with the\nempty string. Values are not necessarily associated with every\nnode. Rather, values tend only to be associated with leaves,\nand with some inner nodes that correspond to keys of interest.\nFor the space-optimized presentation of prefix tree, see compact\nprefix tree.\n\n![Trie](./images/trie.jpg)\n\n*Made with [okso.app](https://okso.app)*\n\n## References\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Trie)\n- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)\n"
  },
  {
    "path": "src/data-structures/trie/README.pt-BR.md",
    "content": "# Árvore de Prefixos (Trie)\n\nNa ciência da computação, uma **trie**, também chamada de árvore digital (digital tree)\ne algumas vezes de _radix tree_ ou _prefix tree_ (tendo em vista que eles\npodem ser pesquisados por prefixos), é um tipo de árvore de pesquisa, uma \nestrutura de dados de árvore ordenada que é usado para armazenar um\nconjunto dinâmico ou matriz associativa onde as chaves são geralmente _strings_.\nAo contrário de uma árvore de pesquisa binária (binary search tree),\nnenhum nó na árvore armazena a chave associada a esse nó; em vez disso,\nsua posição na árvore define a chave com a qual ela está associada.\nTodos os descendentes de um nó possuem em comum o prefixo de uma _string_\nassociada com aquele nó, e a raiz é associada com uma _string_ vazia.\nValores não são necessariamente associados a todos nós. Em vez disso,\nos valores tendem a ser associados apenas a folhas e com alguns nós\ninternos que correspondem a chaves de interesse.\n\nPara a apresentação otimizada do espaço da árvore de prefixo (_prefix tree_),\nveja árvore de prefixo compacto.\n\n![Trie](./images/trie.jpg)\n\n*Made with [okso.app](https://okso.app)*\n\n## Referências\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Trie)\n- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)\n"
  },
  {
    "path": "src/data-structures/trie/README.ru-RU.md",
    "content": "# Префиксное дерево\n\n**Префиксное дерево** (также бор, луч, нагруженное или суффиксное дерево) в информатике - упорядоченная древовидная\nструктура данных, которая используется для хранения динамических множеств или ассоциативных массивов, где\nключом обычно выступают строки. Дерево называется префиксным, потому что поиск осуществляется по префиксам.\n\nВ отличие от бинарного дерева, узлы не содержат ключи, соответствующие узлу. Представляет собой корневое дерево, каждое\nребро которого помечено каким-то символом так, что для любого узла все рёбра, соединяющие этот узел с его сыновьями,\nпомечены разными символами. Некоторые узлы префиксного дерева выделены (на рисунке они подписаны цифрами) и считается,\nчто префиксное дерево содержит данную строку-ключ тогда и только тогда, когда эту строку можно прочитать на пути из\nкорня до некоторого выделенного узла.\n\nТаким образом, в отличие от бинарных деревьев поиска, ключ, идентифицирующий конкретный узел дерева, не явно хранится в\nданном узле, а неявно задаётся положением данного узла в дереве. Получить ключ можно выписыванием подряд символов,\nпомечающих рёбра на пути от корня до узла. Ключ корня дерева — пустая строка. Часто в выделенных узлах хранят\nдополнительную информацию, связанную с ключом, и обычно выделенными являются только листья и, возможно, некоторые\nвнутренние узлы.\n\n![Префиксное дерево](./images/trie.jpg)\n\n*Made with [okso.app](https://okso.app)*\n\nНа рисунке представлено префиксное дерево, содержащее ключи «A», «to», «tea», «ted», «ten», «i», «in», «inn».\n\n## Ссылки\n\n- [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)\n- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)\n"
  },
  {
    "path": "src/data-structures/trie/README.uk-UA.md",
    "content": "# Префіксне дерево\n\n**Префіксне дерево** (Також промінь, навантажене або суфіксне дерево) в інформатиці - впорядкована деревоподібна\nструктура даних, яка використовується для зберігання динамічних множин або асоціативних масивів, де\nключем зазвичай виступають рядки. Дерево називається префіксним, тому що пошук здійснюється за префіксами.\n\nНа відміну від бінарного дерева, вузли не містять ключів, що відповідають вузлу. Являє собою кореневе дерево, кожне\nребро якого позначено якимось символом так, що для будь-якого вузла всі ребра, що з'єднують цей вузол з його синами,\nпозначені різними символами. Деякі вузли префіксного дерева виділені (на малюнку вони підписані цифрами) і вважається,\nщо префіксне дерево містить цей рядок-ключ тоді і тільки тоді, коли цей рядок можна прочитати на шляху з\nкореня до певного виділеного вузла.\n\nТаким чином, на відміну від бінарних дерев пошуку, ключ, що ідентифікує конкретний вузол дерева, не явно зберігається в\nцьому вузлі, а неявно задається положенням цього вузла в дереві. Отримати ключ можна виписуванням поспіль символів,\nпомічають ребра по дорозі від кореня до вузла. Ключ кореня дерева - порожній рядок. Часто у виділених вузлах зберігають\nдодаткову інформацію, пов'язану з ключем, і зазвичай виділеними є тільки листя і, можливо, деякі\nвнутрішні вузли.\n\n![Префіксне дерево](./images/trie.jpg)\n\n*Made with [okso.app](https://okso.app)*\n\nНа малюнку представлено префіксне дерево, що містить ключі. «A», «to», «tea», «ted», «ten», «i», «in», «inn».\n\n## Посилання\n\n- [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)\n"
  },
  {
    "path": "src/data-structures/trie/README.zh-CN.md",
    "content": "# 字典树\n\n在计算机科学中, **字典树(trie,中文又被称为”单词查找树“或 ”键树“)**, 也称为数字树,有时候也被称为基数树或前缀树（因为它们可以通过前缀搜索）,它是一种搜索树--一种已排序的数据结构,通常用于存储动态集或键为字符串的关联数组。\n\n与二叉搜索树不同, 树上没有节点存储与该节点关联的键; 相反,节点在树上的位置定义了与之关联的键。一个节点的全部后代节点都有一个与该节点关联的通用的字符串前缀, 与根节点关联的是空字符串。\n\n值对于字典树中关联的节点来说,不是必需的,相反,值往往和相关的叶子相关,以及与一些键相关的内部节点相关。\n\n有关字典树的空间优化示意,请参阅紧凑前缀树\n\n![Trie](./images/trie.jpg)\n\n*Made with [okso.app](https://okso.app)*\n\n## 参考\n\n- [Wikipedia](https://en.wikipedia.org/wiki/Trie)\n- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)\n"
  },
  {
    "path": "src/data-structures/trie/Trie.js",
    "content": "import TrieNode from './TrieNode';\n\n// Character that we will use for trie tree root.\nconst HEAD_CHARACTER = '*';\n\nexport default class Trie {\n  constructor() {\n    this.head = new TrieNode(HEAD_CHARACTER);\n  }\n\n  /**\n   * @param {string} word\n   * @return {Trie}\n   */\n  addWord(word) {\n    const characters = Array.from(word);\n    let currentNode = this.head;\n\n    for (let charIndex = 0; charIndex < characters.length; charIndex += 1) {\n      const isComplete = charIndex === characters.length - 1;\n      currentNode = currentNode.addChild(characters[charIndex], isComplete);\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {string} word\n   * @return {Trie}\n   */\n  deleteWord(word) {\n    const depthFirstDelete = (currentNode, charIndex = 0) => {\n      if (charIndex >= word.length) {\n        // Return if we're trying to delete the character that is out of word's scope.\n        return;\n      }\n\n      const character = word[charIndex];\n      const nextNode = currentNode.getChild(character);\n\n      if (nextNode == null) {\n        // Return if we're trying to delete a word that has not been added to the Trie.\n        return;\n      }\n\n      // Go deeper.\n      depthFirstDelete(nextNode, charIndex + 1);\n\n      // Since we're going to delete a word let's un-mark its last character isCompleteWord flag.\n      if (charIndex === (word.length - 1)) {\n        nextNode.isCompleteWord = false;\n      }\n\n      // childNode is deleted only if:\n      // - childNode has NO children\n      // - childNode.isCompleteWord === false\n      currentNode.removeChild(character);\n    };\n\n    // Start depth-first deletion from the head node.\n    depthFirstDelete(this.head);\n\n    return this;\n  }\n\n  /**\n   * @param {string} word\n   * @return {string[]}\n   */\n  suggestNextCharacters(word) {\n    const lastCharacter = this.getLastCharacterNode(word);\n\n    if (!lastCharacter) {\n      return null;\n    }\n\n    return lastCharacter.suggestChildren();\n  }\n\n  /**\n   * Check if complete word exists in Trie.\n   *\n   * @param {string} word\n   * @return {boolean}\n   */\n  doesWordExist(word) {\n    const lastCharacter = this.getLastCharacterNode(word);\n\n    return !!lastCharacter && lastCharacter.isCompleteWord;\n  }\n\n  /**\n   * @param {string} word\n   * @return {TrieNode}\n   */\n  getLastCharacterNode(word) {\n    const characters = Array.from(word);\n    let currentNode = this.head;\n\n    for (let charIndex = 0; charIndex < characters.length; charIndex += 1) {\n      if (!currentNode.hasChild(characters[charIndex])) {\n        return null;\n      }\n\n      currentNode = currentNode.getChild(characters[charIndex]);\n    }\n\n    return currentNode;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/trie/TrieNode.js",
    "content": "import HashTable from '../hash-table/HashTable';\n\nexport default class TrieNode {\n  /**\n   * @param {string} character\n   * @param {boolean} isCompleteWord\n   */\n  constructor(character, isCompleteWord = false) {\n    this.character = character;\n    this.isCompleteWord = isCompleteWord;\n    this.children = new HashTable();\n  }\n\n  /**\n   * @param {string} character\n   * @return {TrieNode}\n   */\n  getChild(character) {\n    return this.children.get(character);\n  }\n\n  /**\n   * @param {string} character\n   * @param {boolean} isCompleteWord\n   * @return {TrieNode}\n   */\n  addChild(character, isCompleteWord = false) {\n    if (!this.children.has(character)) {\n      this.children.set(character, new TrieNode(character, isCompleteWord));\n    }\n\n    const childNode = this.children.get(character);\n\n    // In cases similar to adding \"car\" after \"carpet\" we need to mark \"r\" character as complete.\n    childNode.isCompleteWord = childNode.isCompleteWord || isCompleteWord;\n\n    return childNode;\n  }\n\n  /**\n   * @param {string} character\n   * @return {TrieNode}\n   */\n  removeChild(character) {\n    const childNode = this.getChild(character);\n\n    // Delete childNode only if:\n    // - childNode has NO children,\n    // - childNode.isCompleteWord === false.\n    if (\n      childNode\n      && !childNode.isCompleteWord\n      && !childNode.hasChildren()\n    ) {\n      this.children.delete(character);\n    }\n\n    return this;\n  }\n\n  /**\n   * @param {string} character\n   * @return {boolean}\n   */\n  hasChild(character) {\n    return this.children.has(character);\n  }\n\n  /**\n   * Check whether current TrieNode has children or not.\n   * @return {boolean}\n   */\n  hasChildren() {\n    return this.children.getKeys().length !== 0;\n  }\n\n  /**\n   * @return {string[]}\n   */\n  suggestChildren() {\n    return [...this.children.getKeys()];\n  }\n\n  /**\n   * @return {string}\n   */\n  toString() {\n    let childrenAsString = this.suggestChildren().toString();\n    childrenAsString = childrenAsString ? `:${childrenAsString}` : '';\n    const isCompleteString = this.isCompleteWord ? '*' : '';\n\n    return `${this.character}${isCompleteString}${childrenAsString}`;\n  }\n}\n"
  },
  {
    "path": "src/data-structures/trie/__test__/Trie.test.js",
    "content": "import Trie from '../Trie';\n\ndescribe('Trie', () => {\n  it('should create trie', () => {\n    const trie = new Trie();\n\n    expect(trie).toBeDefined();\n    expect(trie.head.toString()).toBe('*');\n  });\n\n  it('should add words to trie', () => {\n    const trie = new Trie();\n\n    trie.addWord('cat');\n\n    expect(trie.head.toString()).toBe('*:c');\n    expect(trie.head.getChild('c').toString()).toBe('c:a');\n\n    trie.addWord('car');\n    expect(trie.head.toString()).toBe('*:c');\n    expect(trie.head.getChild('c').toString()).toBe('c:a');\n    expect(trie.head.getChild('c').getChild('a').toString()).toBe('a:t,r');\n    expect(trie.head.getChild('c').getChild('a').getChild('t').toString()).toBe('t*');\n  });\n\n  it('should delete words from trie', () => {\n    const trie = new Trie();\n\n    trie.addWord('carpet');\n    trie.addWord('car');\n    trie.addWord('cat');\n    trie.addWord('cart');\n    expect(trie.doesWordExist('carpet')).toBe(true);\n    expect(trie.doesWordExist('car')).toBe(true);\n    expect(trie.doesWordExist('cart')).toBe(true);\n    expect(trie.doesWordExist('cat')).toBe(true);\n\n    // Try to delete not-existing word first.\n    trie.deleteWord('carpool');\n    expect(trie.doesWordExist('carpet')).toBe(true);\n    expect(trie.doesWordExist('car')).toBe(true);\n    expect(trie.doesWordExist('cart')).toBe(true);\n    expect(trie.doesWordExist('cat')).toBe(true);\n\n    trie.deleteWord('carpet');\n    expect(trie.doesWordExist('carpet')).toEqual(false);\n    expect(trie.doesWordExist('car')).toEqual(true);\n    expect(trie.doesWordExist('cart')).toBe(true);\n    expect(trie.doesWordExist('cat')).toBe(true);\n\n    trie.deleteWord('cat');\n    expect(trie.doesWordExist('car')).toEqual(true);\n    expect(trie.doesWordExist('cart')).toBe(true);\n    expect(trie.doesWordExist('cat')).toBe(false);\n\n    trie.deleteWord('car');\n    expect(trie.doesWordExist('car')).toEqual(false);\n    expect(trie.doesWordExist('cart')).toBe(true);\n\n    trie.deleteWord('cart');\n    expect(trie.doesWordExist('car')).toEqual(false);\n    expect(trie.doesWordExist('cart')).toBe(false);\n  });\n\n  it('should suggests next characters', () => {\n    const trie = new Trie();\n\n    trie.addWord('cat');\n    trie.addWord('cats');\n    trie.addWord('car');\n    trie.addWord('caption');\n\n    expect(trie.suggestNextCharacters('ca')).toEqual(['t', 'r', 'p']);\n    expect(trie.suggestNextCharacters('cat')).toEqual(['s']);\n    expect(trie.suggestNextCharacters('cab')).toBeNull();\n  });\n\n  it('should check if word exists', () => {\n    const trie = new Trie();\n\n    trie.addWord('cat');\n    trie.addWord('cats');\n    trie.addWord('carpet');\n    trie.addWord('car');\n    trie.addWord('caption');\n\n    expect(trie.doesWordExist('cat')).toBe(true);\n    expect(trie.doesWordExist('cats')).toBe(true);\n    expect(trie.doesWordExist('carpet')).toBe(true);\n    expect(trie.doesWordExist('car')).toBe(true);\n    expect(trie.doesWordExist('cap')).toBe(false);\n    expect(trie.doesWordExist('call')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/data-structures/trie/__test__/TrieNode.test.js",
    "content": "import TrieNode from '../TrieNode';\n\ndescribe('TrieNode', () => {\n  it('should create trie node', () => {\n    const trieNode = new TrieNode('c', true);\n\n    expect(trieNode.character).toBe('c');\n    expect(trieNode.isCompleteWord).toBe(true);\n    expect(trieNode.toString()).toBe('c*');\n  });\n\n  it('should add child nodes', () => {\n    const trieNode = new TrieNode('c');\n\n    trieNode.addChild('a', true);\n    trieNode.addChild('o');\n\n    expect(trieNode.toString()).toBe('c:a,o');\n  });\n\n  it('should get child nodes', () => {\n    const trieNode = new TrieNode('c');\n\n    trieNode.addChild('a');\n    trieNode.addChild('o');\n\n    expect(trieNode.getChild('a').toString()).toBe('a');\n    expect(trieNode.getChild('a').character).toBe('a');\n    expect(trieNode.getChild('o').toString()).toBe('o');\n    expect(trieNode.getChild('b')).toBeUndefined();\n  });\n\n  it('should check if node has children', () => {\n    const trieNode = new TrieNode('c');\n\n    expect(trieNode.hasChildren()).toBe(false);\n\n    trieNode.addChild('a');\n\n    expect(trieNode.hasChildren()).toBe(true);\n  });\n\n  it('should check if node has specific child', () => {\n    const trieNode = new TrieNode('c');\n\n    trieNode.addChild('a');\n    trieNode.addChild('o');\n\n    expect(trieNode.hasChild('a')).toBe(true);\n    expect(trieNode.hasChild('o')).toBe(true);\n    expect(trieNode.hasChild('b')).toBe(false);\n  });\n\n  it('should suggest next children', () => {\n    const trieNode = new TrieNode('c');\n\n    trieNode.addChild('a');\n    trieNode.addChild('o');\n\n    expect(trieNode.suggestChildren()).toEqual(['a', 'o']);\n  });\n\n  it('should delete child node if the child node has NO children', () => {\n    const trieNode = new TrieNode('c');\n    trieNode.addChild('a');\n    expect(trieNode.hasChild('a')).toBe(true);\n\n    trieNode.removeChild('a');\n    expect(trieNode.hasChild('a')).toBe(false);\n  });\n\n  it('should NOT delete child node if the child node has children', () => {\n    const trieNode = new TrieNode('c');\n    trieNode.addChild('a');\n    const childNode = trieNode.getChild('a');\n    childNode.addChild('r');\n\n    trieNode.removeChild('a');\n    expect(trieNode.hasChild('a')).toEqual(true);\n  });\n\n  it('should NOT delete child node if the child node completes a word', () => {\n    const trieNode = new TrieNode('c');\n    const IS_COMPLETE_WORD = true;\n    trieNode.addChild('a', IS_COMPLETE_WORD);\n\n    trieNode.removeChild('a');\n    expect(trieNode.hasChild('a')).toEqual(true);\n  });\n});\n"
  },
  {
    "path": "src/playground/README.md",
    "content": "# Playground\n\nYou may use `playground.js` file to play with data\nstructures and algorithms. The code from `playground.js` may\nbe tested in `./__test__/playground.test.js` file.\n\nTo run tests simply run:\n\n```\nnpm test -- -t 'playground'\n```\n"
  },
  {
    "path": "src/playground/__test__/playground.test.js",
    "content": "import playground from '../playground';\n\ndescribe('playground', () => {\n  it('should return correct results', () => {\n    // Replace the next dummy test with your playground function tests.\n    expect(playground()).toBe(120);\n  });\n});\n"
  },
  {
    "path": "src/playground/playground.js",
    "content": "// Import any algorithmic dependencies you need for your playground code here.\nimport factorial from '../algorithms/math/factorial/factorial';\n\n// Write your playground code inside the playground() function.\n// Test your code from __tests__/playground.test.js\n// Launch playground tests by running: npm test -- 'playground'\nfunction playground() {\n  // Replace the next line with your playground code.\n  return factorial(5);\n}\n\nexport default playground;\n"
  },
  {
    "path": "src/utils/comparator/Comparator.js",
    "content": "export default class Comparator {\n  /**\n   * Constructor.\n   * @param {function(a: *, b: *)} [compareFunction] - It may be custom compare function that, let's\n   * say may compare custom objects together.\n   */\n  constructor(compareFunction) {\n    this.compare = compareFunction || Comparator.defaultCompareFunction;\n  }\n\n  /**\n   * Default comparison function. It just assumes that \"a\" and \"b\" are strings or numbers.\n   * @param {(string|number)} a\n   * @param {(string|number)} b\n   * @returns {number}\n   */\n  static defaultCompareFunction(a, b) {\n    if (a === b) {\n      return 0;\n    }\n\n    return a < b ? -1 : 1;\n  }\n\n  /**\n   * Checks if two variables are equal.\n   * @param {*} a\n   * @param {*} b\n   * @return {boolean}\n   */\n  equal(a, b) {\n    return this.compare(a, b) === 0;\n  }\n\n  /**\n   * Checks if variable \"a\" is less than \"b\".\n   * @param {*} a\n   * @param {*} b\n   * @return {boolean}\n   */\n  lessThan(a, b) {\n    return this.compare(a, b) < 0;\n  }\n\n  /**\n   * Checks if variable \"a\" is greater than \"b\".\n   * @param {*} a\n   * @param {*} b\n   * @return {boolean}\n   */\n  greaterThan(a, b) {\n    return this.compare(a, b) > 0;\n  }\n\n  /**\n   * Checks if variable \"a\" is less than or equal to \"b\".\n   * @param {*} a\n   * @param {*} b\n   * @return {boolean}\n   */\n  lessThanOrEqual(a, b) {\n    return this.lessThan(a, b) || this.equal(a, b);\n  }\n\n  /**\n   * Checks if variable \"a\" is greater than or equal to \"b\".\n   * @param {*} a\n   * @param {*} b\n   * @return {boolean}\n   */\n  greaterThanOrEqual(a, b) {\n    return this.greaterThan(a, b) || this.equal(a, b);\n  }\n\n  /**\n   * Reverses the comparison order.\n   */\n  reverse() {\n    const compareOriginal = this.compare;\n    this.compare = (a, b) => compareOriginal(b, a);\n  }\n}\n"
  },
  {
    "path": "src/utils/comparator/__test__/Comparator.test.js",
    "content": "import Comparator from '../Comparator';\n\ndescribe('Comparator', () => {\n  it('should compare with default comparator function', () => {\n    const comparator = new Comparator();\n\n    expect(comparator.equal(0, 0)).toBe(true);\n    expect(comparator.equal(0, 1)).toBe(false);\n    expect(comparator.equal('a', 'a')).toBe(true);\n    expect(comparator.lessThan(1, 2)).toBe(true);\n    expect(comparator.lessThan(-1, 2)).toBe(true);\n    expect(comparator.lessThan('a', 'b')).toBe(true);\n    expect(comparator.lessThan('a', 'ab')).toBe(true);\n    expect(comparator.lessThan(10, 2)).toBe(false);\n    expect(comparator.lessThanOrEqual(10, 2)).toBe(false);\n    expect(comparator.lessThanOrEqual(1, 1)).toBe(true);\n    expect(comparator.lessThanOrEqual(0, 0)).toBe(true);\n    expect(comparator.greaterThan(0, 0)).toBe(false);\n    expect(comparator.greaterThan(10, 0)).toBe(true);\n    expect(comparator.greaterThanOrEqual(10, 0)).toBe(true);\n    expect(comparator.greaterThanOrEqual(10, 10)).toBe(true);\n    expect(comparator.greaterThanOrEqual(0, 10)).toBe(false);\n  });\n\n  it('should compare with custom comparator function', () => {\n    const comparator = new Comparator((a, b) => {\n      if (a.length === b.length) {\n        return 0;\n      }\n\n      return a.length < b.length ? -1 : 1;\n    });\n\n    expect(comparator.equal('a', 'b')).toBe(true);\n    expect(comparator.equal('a', '')).toBe(false);\n    expect(comparator.lessThan('b', 'aa')).toBe(true);\n    expect(comparator.greaterThanOrEqual('a', 'aa')).toBe(false);\n    expect(comparator.greaterThanOrEqual('aa', 'a')).toBe(true);\n    expect(comparator.greaterThanOrEqual('a', 'a')).toBe(true);\n\n    comparator.reverse();\n\n    expect(comparator.equal('a', 'b')).toBe(true);\n    expect(comparator.equal('a', '')).toBe(false);\n    expect(comparator.lessThan('b', 'aa')).toBe(false);\n    expect(comparator.greaterThanOrEqual('a', 'aa')).toBe(true);\n    expect(comparator.greaterThanOrEqual('aa', 'a')).toBe(false);\n    expect(comparator.greaterThanOrEqual('a', 'a')).toBe(true);\n  });\n});\n"
  }
]