diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index b0c2395..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: ci -on: - push: - branches: - - master -permissions: - contents: write -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Configure Git Credentials - run: | - git config user.name github-actions[bot] - git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - uses: actions/setup-python@v5 - with: - python-version: 3.x - - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - uses: actions/cache@v4 - with: - key: mkdocs-material-${{ env.cache_id }} - path: .cache - restore-keys: | - mkdocs-material- - - run: pip install mkdocs-material - - run: mkdocs gh-deploy --force diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3b0dc41..0000000 --- a/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.DS_Store -*.aux -*.out -*.log -*.synctex.gz -*.toc -_minted-* - -# MkDocs' folder -.cache diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..4bac7e0 --- /dev/null +++ b/404.html @@ -0,0 +1,586 @@ + + + + + + + + + + + + + + + + + + + Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 45570d2..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,24 +0,0 @@ -# Contributing to inzva Algorithm Program -Are you an algorithm enthusiast? Or did you just find a bug? It is not important when it comes to contribution, inzva is community driven. We'd love to have contribution from the community. - -## We Develop with Github -We use github to host code, to track issues and feature requests, as well as accept pull requests. - -## All Code Changes Through Pull Requests -Our documents/codes came from different folks and pull requests are the best way to discuss changes to the repository. We actively welcome your pull requests: - -1. Fork the repo and create your branch from `master`. Branch name convention is [username]/[kebab-case-short-branch-name] -2. If you've added/changed TeX files, make sure it is suitable with our format. -3. If you've added/changed code, make sure it is suitable according to our code style. -4. Open your PR and don't forget to fill in the blanks in the PR opening screen. -5. We'll assign a reviewer for the PR and you can discuss the changes afterwards. -6. Congratulations! Your PR has been merged. - -## Report bugs/errors using Github's [issues](https://github.com/inzva/Algorithm-Program/issues) -We use GitHub issues to track bugs/errors. Report a bug by opening a new issue. Please, don't forget to state the issue well. Don't just open the issue with a title. And don't hesitate to propose a fix. Again, we'd love to have your contribution. - -## License -By contributing, you agree that your contributions will be licensed under its MIT License. - -## References -This document was adapted from [here](https://gist.github.com/briandk/3d2e8b3ec8daf5a27a62#file-contributing-md). diff --git a/README.md b/README.md deleted file mode 100644 index a152dff..0000000 --- a/README.md +++ /dev/null @@ -1,287 +0,0 @@ -# Algorithm Program - -inzva Algorithm Program includes lectures, contests, problem-solving sessions and a variety of practices every Saturday, aimed at teaching advanced knowledge of algorithms to university students, spreading algorithmic thinking and providing training which will help them in international contests as well as in their professional lives. - -We prepared this full-fledged program to last weeks in order to grow the algorithm community in its technical capacity and ready the students for international contests. - -The participants are expected to not only have the skills, but also the enthusiasm and motivation for this unique program, which will be completely free of charge. The program will involve experienced editors to lecture the attendees, problem setters to prepare problems every week and reviewers to check their technical accuracy. The minimum required attendance is 60% for the current program, which will be evaluated by considering your presence in lectures and your regular participation in the weekly contests, is required for a participant to receive certificate of graduation. - -Aside from meeting online every Saturday, we will keep in touch via the discord channel of the community. - - -**DATE & LOCATION** - -Regular meetings occurs in Saturdays. Every batch has a different date, we will be publishing the exact dates at [inzva.com](inzva.com) before every program. - - -**MOTIVATION** - -We believe that the main benefit comes from the opportunity to practice with challenging problems and taking a new step into the world of algorithms. Here are some other benefits we think the participants will acquire from the program: - -- Receiving knowledge and personal experience from successful students in the community and getting one-on-one mentorship -- Motivating yourself to improve your knowledge on a subject -- Assessing yourself -- Coding more efficient -- Advanced knowledge of data structures and algorithms -- Learning teamwork and critical thinking -- Getting to know ICPC World better -- Technical adequacy and preparation for job interviews - -**TECHNICAL PROFICIENCY** - -All participants are expected to know a programming language well. Attendees must prepare their own programming environment (computer, IDE, compiler etc.). The whole practice process will run on [HackerRank](https://www.hackerrank.com) - - -All participant who comply with 60% of the course and contests rules, will get a certificate and various surprizes during the program. Provided, it’s about learning, teaching and sharing; not winning. - -**FREQUENTLY ASKED QUESTIONS** - -Every batch has different rules, selecting criterias and application requirements , we will be publishing FAQ at [inzva.com](inzva.com) before every program. - -**HOW TO BE AN EDITOR/PROBLEM SETTER** - -If you want to support the community as an Editor or Problem Setter, and get scholarship from BEV Foundation for your effort , please contact us by sending an email to [algorithm@inzva.com](mailto:algorithm@inzva.com) with the subject “Being an Editor or Problem Setter for Algorithm Program" . - -**BUNDLES** - -| Name | Topics | -|------|-------| -| [01-Intro](https://github.com/inzva/Algorithm-Program/tree/master/bundles/01-intro) | Big O Notation, Recursion, Builtin Data Structures| -| [02-Algorithms-1](https://github.com/inzva/Algorithm-Program/tree/master/bundles/02-algorithms-1) | Binary Search, Ternary Search, Sorting Algorithms, Quickselect, Divide and Conquer| -| [03-Math-1](https://github.com/inzva/Algorithm-Program/tree/master/bundles/03-math-1) | Number Theory, Sieve of Eratosthenes, Inverse Modular, GCD, LCM, Factorization, Combinatorics, Exponentiation, Meet in the Middle| -| [04-Graph-1](https://github.com/inzva/Algorithm-Program/tree/master/bundles/04-graph-1) | Representing Graphs, Tree Traversals (Preorder, Inorder, Postorder), Binary Search Tree, DFS, BFS, Union Find (DSU), Heap| -| [05-DP-1](https://github.com/inzva/Algorithm-Program/tree/master/bundles/05-dp-1) | Greedy Algorithms, Dynamic Programming, Memoization, Knapsack, Coin Problem, LCS, LIS| -| [06-Data-Structures-1](https://github.com/inzva/Algorithm-Program/tree/master/bundles/06-data-structures-1) | Stack, Queue, Deque, Linked List, Prefix Sum, Sparse Table, Binary Indexed Tree, SQRT Decomposition, Segment Tree| -| [07-Graph-2](https://github.com/inzva/Algorithm-Program/tree/master/bundles/07-graph-2) | Bipartate Checking, Topoligical Sort, Shortest Path (Dijkstra, Floyd-Warshall, Bellman Ford), Minimum Spanning Tree (Prim's, Kruskal's)| -| [08-Data-Structures-2](https://github.com/inzva/Algorithm-Program/tree/master/bundles/08-data-structures-2) | Self Balancing Binary Trees, Treap, AVL Tree, Red Black Tree, Lowest Common Ancestor| -| [09-Data-Structures-3](https://github.com/inzva/Algorithm-Program/tree/master/bundles/09-data-structures-3) | Segment Tree with Lazy Propogation, Binary Search on Segment Tree, Mo's Algorithm, Trie| -| [10-DP-2/](https://github.com/inzva/Algorithm-Program/tree/master/bundles/10-dp-2) | Bitmask DP, DP on Rooted Trees, DP on DAGs, Digit DP, Tree Child-Sibling Notation| -| [11-Graph-3](https://github.com/inzva/Algorithm-Program/tree/master/bundles/11-graph-3) | Bridges and Articulation Points, Strongly Connected Components (SCC), BCC, Cycle Finding, Max Flow| -| [12-Math-3](https://github.com/inzva/Algorithm-Program/tree/master/bundles/12-math-3) | Vector Calculus, Area Calculation, Lines and Planes, Intersection, Convex Hull Problem, Rotating Calipers, Closest Pair Problem| -| [13-graph-5](https://github.com/inzva/Algorithm-Program/tree/master/bundles/13-graph-5) | Segment Tree on a Tree, Heavy-Light Decomposition, Centroid Decomposition of a Tree, Subtrees' Set-Swap Technique| -| [14-Algorithms-5](https://github.com/inzva/Algorithm-Program/tree/master/bundles/14-Algorithms-5) |String Matching Algorithms: KMP, Robin-Karp Algorithm, Suffix Array, Longest Common Prefix Array| - - - - - -**All Contests List** - -
- inzva Algorithm Winter Camp - 2018 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Competition Winter Camp 2018 Qualification](https://www.hackerrank.com/inzva-algorithmic-competition-winter-camp-qualification) | No Specific Topic| -| [inzva ACWC 2018 Contest #1](https://www.hackerrank.com/acwc-session-1) | No Specific Topic| -| [inzva ACWC 2018 Contest #2](https://www.hackerrank.com/acwc-session-2) | No Specific Topic| -| [inzva ACWC 2018 Contest #3](https://www.hackerrank.com/acwc-session-3) | No Specific Topic| -| [inzva ACWC 2018 Contest #4](https://www.hackerrank.com/acwc-session-4) | No Specific Topic| -| [inzva ACWC 2018 Contest #5](https://www.hackerrank.com/acwc-session-5) | No Specific Topic| -| [inzva Algorithmic Competition Winter Camp 2018 All Problems](https://www.hackerrank.com/inzva-algorithmic-competition-winter-camp) | No Specific Topic| -
- -
- inzva Algorithm Summer Camp - 2018 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Competition Summer Camp 2018 Qualification](https://www.hackerrank.com/inzva-algorithmic-competition-summer-camp-qualification) | No Specific Topic| -| [inzva Algorithm Competition Summer Camp 2018 Expert Final Contest](www.hackerrank.com/inzva-acsc-expert-final-contest) | No Specific Topic| -| [inzva ACSC Foundation Contest #1](https://www.hackerrank.com/inzva-acsc-foundation-1) | No Specific Topic| -| [inzva ACSC 2018 Foundation Contest #2](https://www.hackerrank.com/inzva-acsc-foundation-2) | No Specific Topic| -| [inzva ACSC 2018 Foundation Contest #3](https://www.hackerrank.com/inzva-acsc-foundation-3) | No Specific Topic| -| [inzva ACSC 2018 Foundation Contest #4](https://www.hackerrank.com/inzva-acsc-foundation-4) | No Specific Topic| -| [inzva ACSC 2018 Foundation Contest #5](https://www.hackerrank.com/inzva-acsc-foundation-5) | No Specific Topic| -| [inzva ACSC 2018 Foundation Contest #6](https://www.hackerrank.com/inzva-acsc-foundation-6) | No Specific Topic| -| [inzva ACSC 2018 Foundation Final](https://www.hackerrank.com/inzva-acsc-foundation-final) | No Specific Topic| -| [inzva ACSC 2018 Advanced Long Contest #1](https://www.hackerrank.com/inzva-acsc-advanced-long-contest-1) | No Specific Topic| -| [inzva ACSC 2018 Advanced Long Contest #2](https://www.hackerrank.com/inzva-acsc-advanced-long-contest-2) | No Specific Topic| -| [inzva ACSC 2018 Advanced Contest #1](https://www.hackerrank.com/inzva-acsc-advanced-daily-1) | No Specific Topic| -| [inzva ACSC 2018 Advanced Contest #2](https://www.hackerrank.com/inzva-acsc-advanced-daily-2) | No Specific Topic| -| [inzva ACSC 2018 Advanced Contest #3](https://www.hackerrank.com/inzva-acsc-advanced-daily-contest-3) | No Specific Topic| -| [inzva ACSC 2018 Advanced Contest #4](https://www.hackerrank.com/inzva-acsc-advanced-daily-contest-4) | No Specific Topic| -| [inzva ACSC 2018 Advanced Final Contest](https://www.hackerrank.com/inzva-acsc-advanced-final-contest) | No Specific Topic| -| [inzva ACSC 2018 Foundation Upsolving](https://www.hackerrank.com/inzva-acsc-foundation-upsolving) | No Specific Topic| -| [inzva ACSC 2018 Advanced Upsolving](https://www.hackerrank.com/inzva-acsc-advanced-upsolving) | No Specific Topic| -| [inzva ACSC 2018 Expert Contest #1](https://www.hackerrank.com/acsc-session-1) | No Specific Topic| -| [inzva ACSC 2018 Expert Contest #2](https://www.hackerrank.com/acsc-session-2) | No Specific Topic| -| [inzva ACSC 2018 Expert Contest #3](https://www.hackerrank.com/acsc-session-3) | No Specific Topic| -| [inzva ACSC 2018 Expert Contest #4](https://www.hackerrank.com/acsc-session-4) | No Specific Topic| -| [inzva ACSC 2018 Expert Contest #5](https://www.hackerrank.com/acsc-session-5) | No Specific Topic| -| [inzva ACSC 2018 Expert Contest #6](https://www.hackerrank.com/acsc-session-6) | No Specific Topic| -| [inzva ACSC 2018 Expert Final](https://www.hackerrank.com/inzva-acsc-expert-final) | No Specific Topic| -
- -
- inzva Algorithm Winter Camp - 2019 - - | Name | Topic | -|------|-------| -| [inzva Algorithmic Competition Winter Camp 2019 Qualification Contest](www.hackerrank.com/inzva-acwc2019-qualification) | No Specific Topic| -| [inzva ACWC 2019 Advanced #1](https://www.hackerrank.com/inzva-acwc-2019-advanced-1) | No Specific Topic| -| [inzva ACWC 2019 Advanced #2](https://www.hackerrank.com/inzva-acwc-2019-advanced-2) | No Specific Topic| -| [inzva ACWC 2019 Advanced #3](https://www.hackerrank.com/inzva-acwc-2019-advanced-3) | No Specific Topic| -| [inzva ACWC 2019 Advanced #4](https://www.hackerrank.com/inzva-acwc-2019-advanced-4) | No Specific Topic| -| [inzva ACWC 2019 Advanced #5](https://www.hackerrank.com/inzva-acwc-2019-advanced-5) | No Specific Topic| -| [inzva ACWC 2019 Advanced Final](https://www.hackerrank.com/inzva-acwc-2019-advanced-final) | No Specific Topic| -| [inzva ACWC 2019 Foundation Problems](https://www.hackerrank.com/inzva-acwc-2019-foundation-problems) | No Specific Topic| -| [inzva ACWC 2019 Advanced Upsolving](https://www.hackerrank.com/inzva-acwc-2019-advanced-upsolving) | No Specific Topic| -| [inzva ACWC 2019 Foundation Final](https://www.hackerrank.com/inzva-acwc-2019-foundation-final) | No Specific Topic| - -
- -
- inzva Algorithm Program - 2018-2019 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Program 2018-2019 Intro Onsite](https://www.hackerrank.com/inzva-01-intro-onsite-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Intro Online](https://www.hackerrank.com/inzva-01-intro-online-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Algorithm Online](https://www.hackerrank.com/inzva-02-algorithm-1-online-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Algorithm Onsite](https://www.hackerrank.com/inzva-02-algorithm-1-onsite-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Math-1 Online](https://www.hackerrank.com/inzva-03-math-1-online-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Math-1 Onsite](https://www.hackerrank.com/inzva-03-math-1-onsite-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Graph-1 Online](https://www.hackerrank.com/inzva-04-graph-1-online-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Graph-1 Onsite](https://www.hackerrank.com/inzva-04-graph-1-onsite-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 DP-1 Online](https://www.hackerrank.com/inzva-05-dp-1-online-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 DP-1 Onsite](https://www.hackerrank.com/inzva-05-dp-1-onsite-2018) | No Specific Topic| -| [inzva Fall Term Contest 2018](https://www.hackerrank.com/inzva-first-term-2018) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Graph-2 Online](https://www.hackerrank.com/inzva-07-graph-2-online-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Graph-2 Onsite](https://www.hackerrank.com/inzva-07-graph-2-onsite-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Data Structures-2 Online](https://www.hackerrank.com/inzva-08-data-structures-2-online-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Data Structures-2 Onsite](https://www.hackerrank.com/inzva-08-data-structures-2-onsite-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Data Structures-3 Online](https://www.hackerrank.com/inzva-09-data-structures-3-online-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Data Structures-3 Onsite](https://www.hackerrank.com/inzva-09-data-structures-3-onsite-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 DP-2 Online](https://www.hackerrank.com/inzva-10-dp-2-online-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 DP-2 Onsite](https://www.hackerrank.com/inzva-10-dp-2-onsite-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Graph-3 Online](https://www.hackerrank.com/inzva-11-graph-3-online-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Graph-3 Onsite](https://www.hackerrank.com/inzva-11-graph-3-onsite-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Math-3 Online](https://www.hackerrank.com/inzva-12-math-3-online-2019) | No Specific Topic| -
- - -
- inzva 15 Week Algorithm Program - 2019 - - | Name | Topic | -|------|-------| -| [inzva 15 Week Algorithm Program 2019 Intro Online](https://www.hackerrank.com/inzva-ap02-01-intro-online) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Intro Onsite](https://www.hackerrank.com/inzva-ap02-01-intro-onsite) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Data Structures-3 Online](https://www.hackerrank.com/inzva-09-data-structures-3-online-2019) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 DP-2 Onsite](https://www.hackerrank.com/inzva-10-dp-2-onsite-2019) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Math Online](https://www.hackerrank.com/inzva-ap02-02-math-online) | No Specific Topic| -| [inzva Algorithm Program 2018-2019 Data Structures-3 Onsite](https://www.hackerrank.com/inzva-09-data-structures-3-onsite-2019) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 DP Online](https://www.hackerrank.com/inzva-ap02-04-dp-online) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Math Onsite](https://www.hackerrank.com/inzva-ap02-02-math-onsite) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 DP Onsite](https://www.hackerrank.com/inzva-ap02-04-dp-onsite) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Graph Online](https://www.hackerrank.com/inzva-ap02-03-graph-online) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Graph Onsite](https://www.hackerrank.com/inzva-ap02-03-graph-onsite) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Data Structures Online](https://www.hackerrank.com/inzva-ap02-05-data-structures-online) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Data Structures Onsite](https://www.hackerrank.com/inzva-ap02-05-data-structures-onsite) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Graph-2 Onsite](https://www.hackerrank.com/inzva-ap02-07-graph-2-onsite) | No Specific Topic| -| [inzva Algorithm Competition Summer Camp 2019 Qualification](https://www.hackerrank.com/inzva-algorithm-competition-summer-camp-2019-qualification) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Data Structures-2 Online](https://www.hackerrank.com/inzva-ap02-08-data-structures-2-online) | No Specific Topic| -| [inzva 15 Week Algorithm Program 2019 Data Structures-2 Onsite](https://www.hackerrank.com/inzva-ap02-08-data-structures-2-onsite) | No Specific Topic| - -
- -
- inzva Algorithm Summer Camp - 2019 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Competition Summer Camp 2019 Qualification](https://www.hackerrank.com/inzva-algorithm-competition-summer-camp-2019-qualification) | No Specific Topic| -| [inzva ACSC 2019 Advanced #1](https://www.hackerrank.com/inzva-acsc-19-advanced-1) | No Specific Topic| -| [inzva ACSC 2019 Advanced #2](https://www.hackerrank.com/inzva-acsc-19-advanced-2) | No Specific Topic| -| [inzva ACSC 2019 Foundation Final](https://www.hackerrank.com/inzva-acsc-19-foundation-final) | No Specific Topic| -| [inzva ACSC 2019 Advanced #3](https://www.hackerrank.com/inzva-acsc-19-advanced-3) | No Specific Topic| -| [inzva ACSC 2019 Advanced #4](https://www.hackerrank.com/inzva-acsc-19-advanced-4) | No Specific Topic| -| [inzva ACSC 2019 Advanced Final](https://www.hackerrank.com/inzva-acsc-19-advanced-final) | No Specific Topic| -| [inzva ACSC 2019 Foundation Problems](https://www.hackerrank.com/inzva-acsc-19-foundation-problems) | No Specific Topic| -| [inzva ACSC 2019 Advanced Upsolving](https://www.hackerrank.com/inzva-acsc-19-advanced-upsolving) | No Specific Topic| -| [inzva ACSC 2019 Advanced #5](https://www.hackerrank.com/inzva-acsc-19-advanced-5) | No Specific Topic| -
- -
- inzva Algorithm Program - 2019-2020 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Program 2019-2020 Qualification](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-qualification) | No Specific Topic| -| [inzva Algorithm Program 2019-2020 Intro Lab 1 ](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-intro-lab-1) |Recursion, Brute-force| -| [inzva Algorithm Program 2019-2020 Intro Lab 2](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-intro-lab-2) | Binary Search, Ternary Search, Sorting Algorithms| -| [inzva Algorithm Program 2019-2020 Math-1 Lab 3](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-math-1-lab-3) | Sieve of Eratosthenes, Modular Arithmetic, GCD, Factorization Algorithms| -| [inzva Algorithm Program 2019-2020 Math-1 Lab 4](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-math-1-lab-4) | Combination, Meet in the Middle, Enumeration| -| [inzva Algorithm Program 2019-2020 Contest-1](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-contest-1) | All of the Above| -| [Inzva Algorithm Program 2019-2020 Graph-1 Lab 5](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-graph-1-lab-5) | Graph Definitions, Representing Graph| -| [Inzva Algorithm Program 2019-2020 Graph-1 Lab 6](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-graph-1-lab-6) | DFS, BFS| -| [Inzva Algorithm Program 2019-2020 Graph-2 Lab 7](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-graph-2-lab-7) | Heap, Priority-Queue, Dijkstra, Bellman-Ford (Shortest Path)| -| [inzva Algorithm Program 2019-2020 Graph-2 Lab 8](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-graph-2-lab-8) |Union Find, Kruskal's Algorithm, Prim's Algorithm (MST)| -| [inzva Algorithm Program 2019-2020 Contest #2](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-contest-2) | All of the Above| -| [Inzva Algorithm Program 2019-2020 Dp-1 Lab 9](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-dp-1-lab-9) | Coin Problem, LIS, Knapsack Problems| -| [Inzva Algorithm Program 2019-2020 DP-2 Lab 10](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-dp-2-lab-10) | Edit Distance, Counting Tilings Problem, Counting the number of solutions| -| [Inzva Algorithm Program 2019-2020 Data Structures-1 Lab 11](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-data-structures-1-lab-11) | Stack, Queue, Deque, Prefix Sum, Sparse Table| -| [inzva Algorithm Program 2019-2020 Data Structures-2 Lab 12](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-data-structures-2-lab-12) | Segment Tree, Lazy Propagation| -| [inzva Algorithm Program 2019-2020 Graph-3 Lab 13](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-graph-3-lab-13) | LCA, SCC| -| [inzva Algorithm Program 2019-2020 Final](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-final) | No Specific Topic| -| [Inzva Algorithm Program 2019-2020 All Problems](https://www.hackerrank.com/inzva-algorithm-program-2019-2020-all-problems) | No Specific Topic| -
- -
- inzva Algorithm Winter Camp - 2020 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Winter Camp 2020 Qualification](https://www.hackerrank.com/inzva-algorithm-winter-camp-2020-qualification) | No Specific Topic| -| [inzva ACWC 2020 Day #1](https://www.hackerrank.com/inzva-winter-camp-2020-day-1) | Sieve of Eratosthenes, Brute-Force, Enumeration, Binary Search, Ternary Search| -| [inzva ACWC 2020 Day #2](https://www.hackerrank.com/inzva-winter-camp-2020-day-2) | DFS, BFS| -| [inzva ACWC 2020 Day #3](https://www.hackerrank.com/inzva-winter-camp-2020-day-3) | Priority Queue, Shortest Path, MST| -| [inzva ACWC 2020 Day #4](https://www.hackerrank.com/inzva-winter-camp-2020-day-4) | Coin Problem, LIS, Knapsack Problems, LCS| -| [inzva ACWC 2020 Foundation Final](https://www.hackerrank.com/inzva-winter-camp-2020-foundation-final) | All of the Above| -| [inzva ACWC 2020 Expert](https://www.hackerrank.com/inzva-acwc-2020-expert) | No Specific Topic| -| [inzva ACWC 2020 Expert Final](https://www.hackerrank.com/inzva-acwc-2020-expert-final) | No Specific Topic| -
- -
- inzva Algorithm Competition League #1 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Competition League Contest #1](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-1) | No Specific Topic| -| [inzva Algorithm Competition League Contest #2](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-2) | No Specific Topic| -| [inzva Algorithm Competition League Contest #3](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-3) | No Specific Topic| -| [inzva Algorithm Competition League Contest #4](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-4) | No Specific Topic| -| [inzva Algorithm Competition League Contest #5](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-5) | No Specific Topic| -| [inzva Algorithm Competition League Contest #6](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-6) | No Specific Topic| -| [inzva Algorithm Competition League Contest #7](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-7) | No Specific Topic| -| [inzva Algorithm Competition League Contest #8](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-8) | No Specific Topic| -| [inzva Algorithm Competition League Contest #9](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-9) | No Specific Topic| -| [inzva Algorithm Competition League Contest #10](https://www.hackerrank.com/inzva-algorithm-competition-league-contest-10) | No Specific Topic| -
- -
- inzva Algorithm Competition League #2 - - | Name | Topic | -|------|-------| -| [inzva Algorithm Competition League 2 Contest #1](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-1) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #2](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-2) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #3](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-3) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #4](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-4) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #5](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-5) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #6](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-6) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #7](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-7) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #8](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-8) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #9](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-9) | No Specific Topic| -| [inzva Algorithm Competition League 2 Contest #10](https://www.hackerrank.com/inzva-algorithm-competition-league-2-contest-10) | No Specific Topic| -| [inzva Algorithm Competition League 2 Upsolving](https://www.hackerrank.com/inzva-algorithm-competition-league-2-upsolving) | No Specific Topic| -
- -
- inzva Algorithm Training Set - - | Name | Topic | -|------|-------| -| [inzva Intermediate Training Set](https://www.hackerrank.com/inzva-intermediate-training-set) | No Specific Topic| -
diff --git a/bundles/02-algorithms-1/latex/binary_search.png b/algorithms/img/binary_search.png similarity index 100% rename from bundles/02-algorithms-1/latex/binary_search.png rename to algorithms/img/binary_search.png diff --git a/bundles/02-algorithms-1/latex/divide_and_conquer.png b/algorithms/img/divide_and_conquer.png similarity index 100% rename from bundles/02-algorithms-1/latex/divide_and_conquer.png rename to algorithms/img/divide_and_conquer.png diff --git a/bundles/01-intro/latex/inzva-logo.png b/algorithms/img/inzva-logo.png similarity index 100% rename from bundles/01-intro/latex/inzva-logo.png rename to algorithms/img/inzva-logo.png diff --git a/bundles/02-algorithms-1/latex/linear_search.png b/algorithms/img/linear_search.png similarity index 100% rename from bundles/02-algorithms-1/latex/linear_search.png rename to algorithms/img/linear_search.png diff --git a/bundles/02-algorithms-1/latex/ternary_search.png b/algorithms/img/ternary_search.png similarity index 100% rename from bundles/02-algorithms-1/latex/ternary_search.png rename to algorithms/img/ternary_search.png diff --git a/algorithms/index.html b/algorithms/index.html new file mode 100644 index 0000000..015b1dc --- /dev/null +++ b/algorithms/index.html @@ -0,0 +1,1596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Algorithms - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Algorithms + +

+ +
+ + +

Editor: Kadir Emre Oto

+

Reviewers: Muhammed Burak Buğrul, Tahsin Enes Kuru

+

Search Algorithms

+

It may be necessary to determine if an array or solution set contains a specific data, and we call this finding proccess searching. In this article, three most common search algorithms will be discussed: linear search, binary search, and ternary search.

+

This visualization may help you understand how the search algorithms work.

+ +

Simplest search algorithm is linear search, also know as sequential search. In this technique, all elements in the collection of the data is checked one by one, if any element matches, algorithm returns the index; otherwise, it returns \(-1\).

+

Its time complexity is \(\mathcal{O}(N)\).

+
+Example for linear search +
Example for linear search
+
+
1
+2
+3
+4
+5
+6
int linearSearch(int *array, int size, int key) {
+    for (int i = 0; i < size; i++)
+        if (array[i] == key)
+            return i;
+    return -1;
+}
+
+ +

We know linear search is quite a slow algorithm because it compares each element of the set with search key, and there is a high-speed searching technique for sorted data instead of linear search, which is binary search. After each comparison, the algorithm eliminates half of the data using the sorting property.

+

We can also use binary search on increasing functions in the same way.

+

Procedure

+
    +
  1. Compare the key with the middle element of the array,
  2. +
  3. If it is a match, return the index of middle.
  4. +
  5. If the key is bigger than the middle, it means that the key must be in the right side of the middle. We can eliminate the left side.
  6. +
  7. If the key is smaller, it should be on the left side. The right side can be ignored.
  8. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(\tfrac{N}{2}\right) + \mathcal{O}(1) \\ +T(N) &= \mathcal{O}(\log N) +\end{align*} +\]

+
+Example for binary search +
Example for binary search
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
int binarySearch(int *array, int size, int key) {
+    int left = 0, right = size, mid;
+
+    while (left < right) {
+        mid = (left + right) / 2;
+
+        if (array[mid] >= key)
+            right = mid;
+        else
+            left = mid + 1;
+    }
+    return array[left] == key ? left : -1;
+}
+
+ +

Suppose that we have a unimodal function, \(f(x)\), on an interval \([l, r]\), and we are asked to find the local minimum or the local maximum value of the function according to the behavior of it.

+

There are two types of unimodal functions:

+
    +
  1. +

    The function, \(f(x)\) strictly increases for \(x \leq m\), reaches a global maximum at \(x = m\), and then strictly decreases for \(m \leq x\). There are no other local maxima.

    +
  2. +
  3. +

    The function, \(f(x)\) strictly decreases for \(x \leq m\), reaches a global minimum at \(x = m\), and then strictly increases for \(m \leq x\). There are no other local minima.

    +
  4. +
+

In this document, we will implement the first type of unimodal function, and the second one can be solved using the same logic.

+

Procedure

+
    +
  1. Choose any two points \(m_1\), and \(m_2\) on the interval \([l, r]\), where \(l < m_1 < m_2 < r\).
  2. +
  3. If \(f(m_1) < f(m_2)\), it means the maxima should be in the interval \([m_1, r]\), so we can ignore the interval \([l, m_1]\), move \(l\) to \(m_1\)
  4. +
  5. Otherwise, \(f(m_1) \geq f(m_2)\), the maxima have to be in the interval \([l, m_2]\), move \(r\) to \(m_2\)
  6. +
  7. If \(r - l < \epsilon\), where \(\epsilon\) is a negligible value, stop the algorithm, return \(l\). Otherwise turn to the step 1.
  8. +
+

\(m_1\) and \(m_2\) can be selected by \(m_1 = l + \frac{r-l}{3}\) and \(m_2 = r - \frac{r-l}{3}\) to avoid increasing the time complexity.

+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(2 \cdot \tfrac{N}{3}\right) + \mathcal{O}(1) \\ +T(N) &= \mathcal{O}(\log N) +\end{align*} +\]

+
+Example for ternary search +
Example for ternary search
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
double f(double x);
+
+double ternarySearch(double left, double right, double eps = 1e-7) {
+    while (right - left > eps) {
+        double mid1 = left + (right - left) / 3;
+        double mid2 = right - (right - left) / 3;
+
+        if (f(mid1) < f(mid2))
+            left = mid1;
+        else
+            right = mid2;
+    }
+    return f(left);
+}
+
+

Sorting Algorithms

+

Sorting algorithms are used to put the elements of an array in a certain order according to the comparison operator. Numerical order or lexicographical orders are the most common ones, and there are a large number of sorting algorithms, but we discuss four of them:

+
    +
  • Insertion Sort
  • +
  • Merge Sort
  • +
  • Quick Sort
  • +
  • Radix Sort
  • +
+

For a better understanding, you are strongly recommended to go into this visualization site after reading the topics.

+

Insertion Sort

+

Think that you are playing a card game and want to sort them before the game. Your sorting strategy is simple: you have already sorted some part and every time you pick up the next card from unsorted part, you insert it into the correct place in sorted part. After you apply this process to all cards, the whole deck would be sorted.

+

This is the basic idea for sorting an array. We assume that the first element of the array is the sorted part, and other elements are in the unsorted part. Now, we choose the leftmost element of the unsorted part, and put it into the sorted part. In this way the left part of the array always remains sorted after every iteration, and when no element is left in the unsorted part, the array will be sorted.

+
1
+2
+3
+4
+5
void insertionSort(int *ar, int size) {
+    for (int i = 1; i < size; i++)
+        for (int j = i - 1; 0 <= j and ar[j] > ar[j + 1]; j--)
+            swap(ar[j], ar[j + 1]);
+}
+
+

Merge Sort

+

Merge Sort is one of the fastest sorting algorithms that uses Divide and Conquer paradigm. The algorithm divides the array into two halves, solves each part recursively using same sorting function and combines them in linear time by selecting the smallest value of the arrays every time.

+

Procedure

+
    +
  1. If the size of the array is 1, it is sorted already, stop the algorithm (base case),
  2. +
  3. Find the middle point of the array, and split it in two,
  4. +
  5. Do the algorithm for these parts separately from the first step,
  6. +
  7. After the two halves got sorted, merge them in linear time and the array will be sorted.
  8. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(\tfrac{N}{2}\right) + \mathcal{O}(N) \\ +T(N) &= \mathcal{O}(N \cdot \log N) +\end{align*} +\]

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
void mergeSort(int *ar, int size) {
+    if (size <= 1) // base case
+        return;
+
+    mergeSort(ar, size / 2); // divide the array into two almost equal parts
+    mergeSort(ar + size / 2, size - size / 2);
+
+    int index = 0, left = 0, right = size / 2; // merge them
+    int *temp = new int[size];
+
+    while (left < size / 2 or right < size) {
+        if (right == size or (left < size / 2 and ar[left] < ar[right]))
+            temp[index++] = ar[left++];
+        else
+            temp[index++] = ar[right++];
+    }
+    for (int i = 0; i < size; i++)
+        ar[i] = temp[i];
+    delete[] temp;
+}
+
+

Quick Sort

+

Quick Sort is also a Divide and Conquer algorithm. The algorithm chooses an element from the array as a pivot and partitions the array around it. Partitioning is arranging the array that satisfies those: the pivot should be put to its correct place, all smaller values should be placed before the pivot, and all greater values should be placed after the pivot. The partitioning can be done in linear time, and after the partitioning, we can use the same sorting function to solve the left part of the pivot and the right part of the pivot recursively.

+

If the sellected pivot cannot divide the array uniformly after the partitioning, the time complexity can reach \(\mathcal{O}(n ^ 2)\) like insertion sort. To avoid this, the pivot can generally be picked randomly.

+

Procedure

+
    +
  1. If the size of the array is \(1\), it is sorted already, stop the algorithm (base case),
  2. +
  3. Choose a pivot randomly,
  4. +
  5. For all values in the array, collect smaller values in the left of the array and greater values in the right of array,
  6. +
  7. Move the pivot to the correct place,
  8. +
  9. Repeat the same algorithm for the left partition and the right partition.
  10. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(\tfrac{N}{10}\right) + T\left(9 \cdot \tfrac{N}{10}\right) + \mathcal{O}(N) \\ +T(N) &= \mathcal{O}(N \cdot \log N) +\end{align*} +\]

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
void quickSort(int *ar, int size) {
+    if (size <= 1) // base case
+        return;
+
+    int position = 1; // find the correct place of pivot
+    swap(ar[0], ar[rand() % size]);
+
+    for (int i = 1; i < size; i++)
+        if (ar[0] > ar[i])
+            swap(ar[i], ar[position++]);
+    swap(ar[0], ar[position - 1]);
+
+    quickSort(ar, position - 1);
+    quickSort(ar + position, size - position);
+}
+
+

Radix Sort

+

Quick Sort and Merge Sort are comparison-based sorting algorithms and cannot run better than \(\mathcal{O}(N \log N)\). However, Radix Sort works in linear time (\(\mathcal{O}(N + K)\), where \(K\) is \(\log(\max(ar))\)).

+

Procedure

+
    +
  1. For each digit from the least significant to the most, sort the array using Counting Sort according to corresponding digit. Counting Sort is used for keys between specific range, and it counts the number of elements which have different key values. After counting the number of distict key values, we can determine the position of elements in the array.
  2. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= \mathcal{O}(N) +\end{align*} +\]

+
 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
+26
+27
+28
+29
+30
+31
void radixSort(int *ar, int size, int base = 10) {
+    int *temp = new int[size];
+    int *count = new int[base]();
+
+    // Find the maximum value.
+    int maxx = ar[0];
+    for (int i = 1; i < size; i++) {
+        if (ar[i] > maxx) {
+            maxx = ar[i];
+        }
+    }
+
+    for (int e = 1; maxx / e > 0; e *= base) {
+        memset(count, 0, sizeof(int) * base);
+
+        for (int i = 0; i < size; i++)
+            count[(ar[i] / e) % base]++;
+
+        for (int i = 1; i < base; i++)
+            count[i] += count[i - 1];
+
+        for (int i = size - 1; 0 <= i; i--)
+            temp[--count[(ar[i] / e) % base]] = ar[i];
+
+        for (int i = 0; i < size; i++)
+            ar[i] = temp[i];
+    }
+
+    delete[] temp;
+    delete[] count;
+}
+
+

Quickselect Algorithm

+

Quickselect is a selection algorithm that finds the \(k^{th}\) smallest element in an unordered list. The algorithm is closely related to QuickSort in partitioning stage; however, instead of recurring for both sides, it recurs only for the part that contains the \(k^{th}\) smallest element.

+

Procedure

+
    +
  1. Choose a pivot randomly,
  2. +
  3. For all values in the array, collect smaller values in the left of the array and greater values in the right of the array,
  4. +
  5. Move the pivot to the correct place,
  6. +
  7. If the current position is equal to \(k\), return the value at the position.
  8. +
  9. If the current position is more than \(k\), repeat the same algorithm for the left partition.
  10. +
  11. Else, update \(k\) and repeat the same algorithm for the right partition.
  12. +
+

Complexity

+
    +
  • In average: \(\mathcal{O}(N)\)
  • +
  • Worst-case: \(\mathcal{O}(N^2)\)
  • +
+
+

Note that this algorithm is fast in practice, but has poor worst-case performance, like quicksort. However, it still performs better on average than other algorithms that find the \(k^{th}\) smallest element in \(\mathcal{O}(n)\) in the worst case.

+
+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
// This function finds the k-th smallest element in arr within size si.
+int QuickSelect(int *arr, int si, int k) {
+    // Check if k is valid and if arr has no less elements than k.
+    if (0 < k && k <= si) {
+        // The quicksort-like partitioning. It is same until we find the index of the pivot.
+        int ind = 0;
+
+        // Get a random pivot to decrease the chance of getting worst-case scenario.
+        swap(arr[si - 1], arr[rand() % si]);
+        for (int j = 0; j < si - 1; j++) {
+            if (arr[j] <= arr[si - 1]) {
+                swap(arr[j], arr[ind]);
+                ind++;
+            }
+        }
+        swap(arr[si - 1], arr[ind]);
+
+        // Now check and recur to appropriate situation.
+        // If the index is equal with k-1 (as our array is 0-indexed) return the value.
+        if (ind == k - 1) {
+            return arr[ind];
+        }
+        // Else check if index is greater than k-1. If it is, recur to the left part.
+        else if (ind > k - 1) {
+            return QuickSelect(arr, ind, k);
+        }
+        // Else, recur to the right part.
+        else {
+            return QuickSelect(arr + ind + 1, si - ind - 1, k - ind - 1);
+        }
+    }
+    // If invalid values is given
+    return INT_MAX;
+}
+
+

Divide and Conquer

+

Divide and Conquer is a well-known paradigm that breaks up the problem into several parts, solves each part independently, and finally combines the solutions to the subproblems into the overall solution. Because each subproblem is solved recursively, they should be the smaller versions of the original problem; and the problem must have a base case to end the recursion.

+

Some example algorithms that use divide and conquer technique:

+
    +
  • Merge Sort
  • +
  • Count Inversions
  • +
  • Finding the Closest Pair of Points
  • +
  • Others
  • +
+
+The Flow of *Divide and Conquer* +
The Flow of Divide and Conquer
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.c8b220af.min.js b/assets/javascripts/bundle.c8b220af.min.js new file mode 100644 index 0000000..34b23f9 --- /dev/null +++ b/assets/javascripts/bundle.c8b220af.min.js @@ -0,0 +1,16 @@ +"use strict";(()=>{var Wi=Object.create;var gr=Object.defineProperty;var Vi=Object.getOwnPropertyDescriptor;var Di=Object.getOwnPropertyNames,Vt=Object.getOwnPropertySymbols,Ni=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,ao=Object.prototype.propertyIsEnumerable;var io=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,$=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&io(e,r,t[r]);if(Vt)for(var r of Vt(t))ao.call(t,r)&&io(e,r,t[r]);return e};var so=(e,t)=>{var r={};for(var o in e)yr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Vt)for(var o of Vt(e))t.indexOf(o)<0&&ao.call(e,o)&&(r[o]=e[o]);return r};var xr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var zi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Di(t))!yr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Vi(t,n))||o.enumerable});return e};var Lt=(e,t,r)=>(r=e!=null?Wi(Ni(e)):{},zi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var co=(e,t,r)=>new Promise((o,n)=>{var i=p=>{try{s(r.next(p))}catch(c){n(c)}},a=p=>{try{s(r.throw(p))}catch(c){n(c)}},s=p=>p.done?o(p.value):Promise.resolve(p.value).then(i,a);s((r=r.apply(e,t)).next())});var lo=xr((Er,po)=>{(function(e,t){typeof Er=="object"&&typeof po!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(k){return!!(k&&k!==document&&k.nodeName!=="HTML"&&k.nodeName!=="BODY"&&"classList"in k&&"contains"in k.classList)}function p(k){var ft=k.type,qe=k.tagName;return!!(qe==="INPUT"&&a[ft]&&!k.readOnly||qe==="TEXTAREA"&&!k.readOnly||k.isContentEditable)}function c(k){k.classList.contains("focus-visible")||(k.classList.add("focus-visible"),k.setAttribute("data-focus-visible-added",""))}function l(k){k.hasAttribute("data-focus-visible-added")&&(k.classList.remove("focus-visible"),k.removeAttribute("data-focus-visible-added"))}function f(k){k.metaKey||k.altKey||k.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(k){o=!1}function d(k){s(k.target)&&(o||p(k.target))&&c(k.target)}function y(k){s(k.target)&&(k.target.classList.contains("focus-visible")||k.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(k.target))}function L(k){document.visibilityState==="hidden"&&(n&&(o=!0),X())}function X(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function ee(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(k){k.target.nodeName&&k.target.nodeName.toLowerCase()==="html"||(o=!1,ee())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),X(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var qr=xr((dy,On)=>{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var $a=/["'&<>]/;On.exports=Pa;function Pa(e){var t=""+e,r=$a.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Rt=="object"&&typeof Yr=="object"?Yr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Rt=="object"?Rt.ClipboardJS=r():t.ClipboardJS=r()})(Rt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Ui}});var a=i(279),s=i.n(a),p=i(370),c=i.n(p),l=i(817),f=i.n(l);function u(D){try{return document.execCommand(D)}catch(A){return!1}}var d=function(A){var M=f()(A);return u("cut"),M},y=d;function L(D){var A=document.documentElement.getAttribute("dir")==="rtl",M=document.createElement("textarea");M.style.fontSize="12pt",M.style.border="0",M.style.padding="0",M.style.margin="0",M.style.position="absolute",M.style[A?"right":"left"]="-9999px";var F=window.pageYOffset||document.documentElement.scrollTop;return M.style.top="".concat(F,"px"),M.setAttribute("readonly",""),M.value=D,M}var X=function(A,M){var F=L(A);M.container.appendChild(F);var V=f()(F);return u("copy"),F.remove(),V},ee=function(A){var M=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},F="";return typeof A=="string"?F=X(A,M):A instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(A==null?void 0:A.type)?F=X(A.value,M):(F=f()(A),u("copy")),F},J=ee;function k(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?k=function(M){return typeof M}:k=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},k(D)}var ft=function(){var A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=A.action,F=M===void 0?"copy":M,V=A.container,Y=A.target,$e=A.text;if(F!=="copy"&&F!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&k(Y)==="object"&&Y.nodeType===1){if(F==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(F==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if($e)return J($e,{container:V});if(Y)return F==="cut"?y(Y):J(Y,{container:V})},qe=ft;function Fe(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(M){return typeof M}:Fe=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},Fe(D)}function ki(D,A){if(!(D instanceof A))throw new TypeError("Cannot call a class as a function")}function no(D,A){for(var M=0;M0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=Fe(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var Y=this;this.listener=c()(V,"click",function($e){return Y.onClick($e)})}},{key:"onClick",value:function(V){var Y=V.delegateTarget||V.currentTarget,$e=this.action(Y)||"copy",Wt=qe({action:$e,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(Wt?"success":"error",{action:$e,text:Wt,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return vr("action",V)}},{key:"defaultTarget",value:function(V){var Y=vr("target",V);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(V){return vr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(V,Y)}},{key:"cut",value:function(V){return y(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof V=="string"?[V]:V,$e=!!document.queryCommandSupported;return Y.forEach(function(Wt){$e=$e&&!!document.queryCommandSupported(Wt)}),$e}}]),M}(s()),Ui=Fi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,p){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(p))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(l,f,u,d,y){var L=c.apply(this,arguments);return l.addEventListener(u,L,y),{destroy:function(){l.removeEventListener(u,L,y)}}}function p(l,f,u,d,y){return typeof l.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return s(L,f,u,d,y)}))}function c(l,f,u,d){return function(y){y.delegateTarget=a(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=p},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function p(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(y))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,d,y);if(a.nodeList(u))return l(u,d,y);if(a.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,y)})}}}function f(u,d,y){return s(document.body,u,d,y)}o.exports=p},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var p=window.getSelection(),c=document.createRange();c.selectNodeContents(i),p.removeAllRanges(),p.addRange(c),a=p.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var p=this.e||(this.e={});return(p[i]||(p[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var p=this;function c(){p.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),p=0,c=s.length;for(p;p0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function N(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||p(d,L)})},y&&(n[d]=y(n[d])))}function p(d,y){try{c(o[d](y))}catch(L){u(i[0][3],L)}}function c(d){d.value instanceof nt?Promise.resolve(d.value.v).then(l,f):u(i[0][2],d)}function l(d){p("next",d)}function f(d){p("throw",d)}function u(d,y){d(y),i.shift(),i.length&&p(i[0][0],i[0][1])}}function uo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof he=="function"?he(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,p){a=e[i](a),n(s,p,a.done,a.value)})}}function n(i,a,s,p){Promise.resolve(p).then(function(c){i({value:c,done:s})},a)}}function H(e){return typeof e=="function"}function ut(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Nt=ut(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Qe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ue=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=he(a),p=s.next();!p.done;p=s.next()){var c=p.value;c.remove(this)}}catch(L){t={error:L}}finally{try{p&&!p.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var l=this.initialTeardown;if(H(l))try{l()}catch(L){i=L instanceof Nt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=he(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{ho(y)}catch(L){i=i!=null?i:[],L instanceof Nt?i=q(q([],N(i)),N(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Nt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ho(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Qe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Qe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=Ue.EMPTY;function zt(e){return e instanceof Ue||e&&"closed"in e&&H(e.remove)&&H(e.add)&&H(e.unsubscribe)}function ho(e){H(e)?e():e.unsubscribe()}var Pe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var dt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new Ue(function(){o.currentObservers=null,Qe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new To(r,o)},t}(j);var To=function(e){oe(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(g);var _r=function(e){oe(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(g);var _t={now:function(){return(_t.delegate||Date).now()},delegate:void 0};var At=function(e){oe(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=_t);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,p=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+p)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),p=0;p0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(gt);var Lo=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(yt);var kr=new Lo(Oo);var Mo=function(e){oe(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=vt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&o===r._scheduled&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(vt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(gt);var _o=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o;r?o=r.id:(o=this._scheduled,this._scheduled=void 0);var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(yt);var me=new _o(Mo);var S=new j(function(e){return e.complete()});function Kt(e){return e&&H(e.schedule)}function Hr(e){return e[e.length-1]}function Xe(e){return H(Hr(e))?e.pop():void 0}function ke(e){return Kt(Hr(e))?e.pop():void 0}function Yt(e,t){return typeof Hr(e)=="number"?e.pop():t}var xt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Bt(e){return H(e==null?void 0:e.then)}function Gt(e){return H(e[bt])}function Jt(e){return Symbol.asyncIterator&&H(e==null?void 0:e[Symbol.asyncIterator])}function Xt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Zt=Zi();function er(e){return H(e==null?void 0:e[Zt])}function tr(e){return fo(this,arguments,function(){var r,o,n,i;return Dt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,nt(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,nt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,nt(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function rr(e){return H(e==null?void 0:e.getReader)}function U(e){if(e instanceof j)return e;if(e!=null){if(Gt(e))return ea(e);if(xt(e))return ta(e);if(Bt(e))return ra(e);if(Jt(e))return Ao(e);if(er(e))return oa(e);if(rr(e))return na(e)}throw Xt(e)}function ea(e){return new j(function(t){var r=e[bt]();if(H(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ta(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?b(function(n,i){return e(n,i,o)}):le,Te(1),r?Ve(t):Qo(function(){return new nr}))}}function jr(e){return e<=0?function(){return S}:E(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new g}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,p=s===void 0?!0:s;return function(c){var l,f,u,d=0,y=!1,L=!1,X=function(){f==null||f.unsubscribe(),f=void 0},ee=function(){X(),l=u=void 0,y=L=!1},J=function(){var k=l;ee(),k==null||k.unsubscribe()};return E(function(k,ft){d++,!L&&!y&&X();var qe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!y&&(f=Ur(J,p))}),qe.subscribe(ft),!l&&d>0&&(l=new at({next:function(Fe){return qe.next(Fe)},error:function(Fe){L=!0,X(),f=Ur(ee,n,Fe),qe.error(Fe)},complete:function(){y=!0,X(),f=Ur(ee,a),qe.complete()}}),U(k).subscribe(l))})(c)}}function Ur(e,t){for(var r=[],o=2;oe.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function R(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ie(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var wa=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(_e(1),Q(void 0),m(()=>Ie()||document.body),G(1));function et(e){return wa.pipe(m(t=>e.contains(t)),K())}function Ht(e,t){return C(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?kt(r=>Le(+!r*t)):le,Q(e.matches(":hover"))))}function Jo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Jo(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Jo(o,n);return o}function sr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function wt(e){let t=x("script",{src:e});return C(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(v(()=>$r(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),Te(1))))}var Xo=new g,Ta=C(()=>typeof ResizeObserver=="undefined"?wt("https://unpkg.com/resize-observer-polyfill"):I(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>Xo.next(t)))),v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function ce(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Ta.pipe(w(r=>r.observe(t)),v(r=>Xo.pipe(b(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ce(e)),Q(ce(e)))}function Tt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function cr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Zo(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function De(e){return{x:e.offsetLeft,y:e.offsetTop}}function en(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function tn(e){return O(h(window,"load"),h(window,"resize")).pipe(Me(0,me),m(()=>De(e)),Q(De(e)))}function pr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ne(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(Me(0,me),m(()=>pr(e)),Q(pr(e)))}var rn=new g,Sa=C(()=>I(new IntersectionObserver(e=>{for(let t of e)rn.next(t)},{threshold:0}))).pipe(v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function tt(e){return Sa.pipe(w(t=>t.observe(e)),v(t=>rn.pipe(b(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function on(e,t=16){return Ne(e).pipe(m(({y:r})=>{let o=ce(e),n=Tt(e);return r>=n.height-o.height-t}),K())}var lr={drawer:R("[data-md-toggle=drawer]"),search:R("[data-md-toggle=search]")};function nn(e){return lr[e].checked}function Je(e,t){lr[e].checked!==t&&lr[e].click()}function ze(e){let t=lr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Oa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function La(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function an(){let e=h(window,"keydown").pipe(b(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:nn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),b(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!Oa(o,r)}return!0}),pe());return La().pipe(v(t=>t?S:e))}function ye(){return new URL(location.href)}function lt(e,t=!1){if(B("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function sn(){return new g}function cn(){return location.hash.slice(1)}function pn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Ma(e){return O(h(window,"hashchange"),e).pipe(m(cn),Q(cn()),b(t=>t.length>0),G(1))}function ln(e){return Ma(e).pipe(m(t=>fe(`[id="${t}"]`)),b(t=>typeof t!="undefined"))}function $t(e){let t=matchMedia(e);return ir(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function mn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function Nr(e,t){return e.pipe(v(r=>r?t():S))}function zr(e,t){return new j(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function je(e,t){return zr(e,t).pipe(v(r=>r.text()),m(r=>JSON.parse(r)),G(1))}function fn(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),G(1))}function un(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),G(1))}function dn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function hn(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(dn),Q(dn()))}function bn(){return{width:innerWidth,height:innerHeight}}function vn(){return h(window,"resize",{passive:!0}).pipe(m(bn),Q(bn()))}function gn(){return z([hn(),vn()]).pipe(m(([e,t])=>({offset:e,size:t})),G(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(te("size")),n=z([o,r]).pipe(m(()=>De(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:a,size:s},{x:p,y:c}])=>({offset:{x:a.x-p,y:a.y-c+i},size:s})))}function _a(e){return h(e,"message",t=>t.data)}function Aa(e){let t=new g;return t.subscribe(r=>e.postMessage(r)),t}function yn(e,t=new Worker(e)){let r=_a(t),o=Aa(t),n=new g;n.subscribe(o);let i=o.pipe(Z(),ie(!0));return n.pipe(Z(),Re(r.pipe(W(i))),pe())}var Ca=R("#__config"),St=JSON.parse(Ca.textContent);St.base=`${new URL(St.base,ye())}`;function xe(){return St}function B(e){return St.features.includes(e)}function Ee(e,t){return typeof t!="undefined"?St.translations[e].replace("#",t.toString()):St.translations[e]}function Se(e,t=document){return R(`[data-md-component=${e}]`,t)}function ae(e,t=document){return P(`[data-md-component=${e}]`,t)}function ka(e){let t=R(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>R(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function xn(e){if(!B("announce.dismiss")||!e.childElementCount)return S;if(!e.hidden){let t=R(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new g;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),ka(e).pipe(w(r=>t.next(r)),_(()=>t.complete()),m(r=>$({ref:e},r)))})}function Ha(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function En(e,t){let r=new g;return r.subscribe(({hidden:o})=>{e.hidden=o}),Ha(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))}function Pt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function wn(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function Tn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function Sn(e){return x("button",{class:"md-clipboard md-icon",title:Ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var Ln=Lt(qr());function Qr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(p=>!e.terms[p]).reduce((p,c)=>[...p,x("del",null,(0,Ln.default)(c))," "],[]).slice(0,-1),i=xe(),a=new URL(e.location,i.base);B("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,p])=>p).reduce((p,[c])=>`${p} ${c}`.trim(),""));let{tags:s}=xe();return x("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&x("nav",{class:"md-tags"},e.tags.map(p=>{let c=s?p in s?`md-tag-icon md-tag--${s[p]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${c}`},p)})),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Ee("search.result.term.missing"),": ",...n)))}function Mn(e){let t=e[0].score,r=[...e],o=xe(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(l=>l.scoreQr(l,1)),...p.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,p.length>0&&p.length===1?Ee("search.result.more.one"):Ee("search.result.more.other",p.length))),...p.map(l=>Qr(l,1)))]:[]];return x("li",{class:"md-search-result__item"},c)}function _n(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?sr(r):r)))}function Kr(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function An(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function Ra(e){var o;let t=xe(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function Cn(e,t){var o;let r=xe();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Ee("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map(Ra)))}var Ia=0;function ja(e){let t=z([et(e),Ht(e)]).pipe(m(([o,n])=>o||n),K()),r=C(()=>Zo(e)).pipe(ne(Ne),pt(1),He(t),m(()=>en(e)));return t.pipe(Ae(o=>o),v(()=>z([t,r])),m(([o,n])=>({active:o,offset:n})),pe())}function Fa(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Ia++}`;return C(()=>{let i=new g,a=new _r(!1);i.pipe(Z(),ie(!1)).subscribe(a);let s=a.pipe(kt(c=>Le(+!c*250,kr)),K(),v(c=>c?r:S),w(c=>c.id=n),pe());z([i.pipe(m(({active:c})=>c)),s.pipe(v(c=>Ht(c,250)),Q(!1))]).pipe(m(c=>c.some(l=>l))).subscribe(a);let p=a.pipe(b(c=>c),re(s,o),m(([c,l,{size:f}])=>{let u=e.getBoundingClientRect(),d=u.width/2;if(l.role==="tooltip")return{x:d,y:8+u.height};if(u.y>=f.height/2){let{height:y}=ce(l);return{x:d,y:-16-y}}else return{x:d,y:16+u.height}}));return z([s,i,p]).subscribe(([c,{offset:l},f])=>{c.style.setProperty("--md-tooltip-host-x",`${l.x}px`),c.style.setProperty("--md-tooltip-host-y",`${l.y}px`),c.style.setProperty("--md-tooltip-x",`${f.x}px`),c.style.setProperty("--md-tooltip-y",`${f.y}px`),c.classList.toggle("md-tooltip2--top",f.y<0),c.classList.toggle("md-tooltip2--bottom",f.y>=0)}),a.pipe(b(c=>c),re(s,(c,l)=>l),b(c=>c.role==="tooltip")).subscribe(c=>{let l=ce(R(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${l.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(K(),ve(me),re(s)).subscribe(([c,l])=>{l.classList.toggle("md-tooltip2--active",c)}),z([a.pipe(b(c=>c)),s]).subscribe(([c,l])=>{l.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(b(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),ja(e).pipe(w(c=>i.next(c)),_(()=>i.complete()),m(c=>$({ref:e},c)))})}function mt(e,{viewport$:t},r=document.body){return Fa(e,{content$:new j(o=>{let n=e.title,i=wn(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function Ua(e,t){let r=C(()=>z([tn(e),Ne(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:a,height:s}=ce(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return et(e).pipe(v(o=>r.pipe(m(n=>({active:o,offset:n})),Te(+!o||1/0))))}function kn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),tt(e).pipe(W(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),O(i.pipe(b(({active:s})=>s)),i.pipe(_e(250),b(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Me(16,me)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(a),b(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),h(n,"mousedown").pipe(W(a),re(i)).subscribe(([s,{active:p}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(p){s.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(c=Ie())==null||c.blur()}}),r.pipe(W(a),b(s=>s===o),Ge(125)).subscribe(()=>e.focus()),Ua(e,t).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function Wa(e){return e.tagName==="CODE"?P(".c, .c1, .cm",e):[e]}function Va(e){let t=[];for(let r of Wa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,p]=a;if(typeof p=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function Hn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Va(t)){let[,p]=s.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${p})`,e)&&(a.set(p,Tn(p,i)),s.replaceWith(a.get(p)))}return a.size===0?S:C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=[];for(let[l,f]of a)c.push([R(".md-typeset",f),R(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(p)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of c)l?Hn(f,u):Hn(u,f)}),O(...[...a].map(([,l])=>kn(l,t,{target$:r}))).pipe(_(()=>s.complete()),pe())})}function $n(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return $n(t)}}function Pn(e,t){return C(()=>{let r=$n(e);return typeof r!="undefined"?fr(r,e,t):S})}var Rn=Lt(Br());var Da=0;function In(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return In(t)}}function Na(e){return ge(e).pipe(m(({width:t})=>({scrollable:Tt(e).width>t})),te("scrollable"))}function jn(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new g,i=n.pipe(jr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Rn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Da++}`;let l=Sn(c.id);c.insertBefore(l,e),B("content.tooltips")&&a.push(mt(l,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=In(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||B("content.code.annotate"))){let l=fr(c,e,t);a.push(ge(s).pipe(W(i),m(({width:f,height:u})=>f&&u),K(),v(f=>f?l:S)))}}return P(":scope > span[id]",e).length&&e.classList.add("md-code__content"),Na(e).pipe(w(c=>n.next(c)),_(()=>n.complete()),m(c=>$({ref:e},c)),Re(...a))});return B("content.lazy")?tt(e).pipe(b(n=>n),Te(1),v(()=>o)):o}function za(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),b(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(b(n=>n||!o),w(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Fn(e,t){return C(()=>{let r=new g;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),za(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}var Un=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.flowchartTitleText{fill:var(--md-mermaid-label-fg-color)}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}.classDiagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs marker.marker.composition.class path,defs marker.marker.dependency.class path,defs marker.marker.extension.class path{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs marker.marker.aggregation.class path{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}.statediagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.entityTitleText{fill:var(--md-mermaid-label-fg-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}text:not([class]):last-child{fill:var(--md-mermaid-label-fg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Gr,Qa=0;function Ka(){return typeof mermaid=="undefined"||mermaid instanceof Element?wt("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):I(void 0)}function Wn(e){return e.classList.remove("mermaid"),Gr||(Gr=Ka().pipe(w(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Un,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),G(1))),Gr.subscribe(()=>co(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Qa++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Gr.pipe(m(()=>({ref:e})))}var Vn=x("table");function Dn(e){return e.replaceWith(Vn),Vn.replaceWith(An(e)),I({ref:e})}function Ya(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>R(`label[for="${r.id}"]`))))).pipe(Q(R(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Nn(e,{viewport$:t,target$:r}){let o=R(".tabbed-labels",e),n=P(":scope > input",e),i=Kr("prev");e.append(i);let a=Kr("next");return e.append(a),C(()=>{let s=new g,p=s.pipe(Z(),ie(!0));z([s,ge(e),tt(e)]).pipe(W(p),Me(1,me)).subscribe({next([{active:c},l]){let f=De(c),{width:u}=ce(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=pr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([Ne(o),ge(o)]).pipe(W(p)).subscribe(([c,l])=>{let f=Tt(o);i.hidden=c.x<16,a.hidden=c.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(a,"click").pipe(m(()=>1))).pipe(W(p)).subscribe(c=>{let{width:l}=ce(o);o.scrollBy({left:l*c,behavior:"smooth"})}),r.pipe(W(p),b(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let l=R(`label[for="${c.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(p),b(f=>!(f.metaKey||f.ctrlKey)),w(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&s.pipe(Ce(1),re(t)).subscribe(([{active:c},{offset:l}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of P("[data-tabs]"))for(let L of P(":scope > input",y)){let X=R(`label[for="${L.id}"]`);if(X!==c&&X.innerText.trim()===f){X.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),s.pipe(W(p)).subscribe(()=>{for(let c of P("audio, video",e))c.pause()}),Ya(n).pipe(w(c=>s.next(c)),_(()=>s.complete()),m(c=>$({ref:e},c)))}).pipe(Ke(se))}function zn(e,{viewport$:t,target$:r,print$:o}){return O(...P(".annotate:not(.highlight)",e).map(n=>Pn(n,{target$:r,print$:o})),...P("pre:not(.mermaid) > code",e).map(n=>jn(n,{target$:r,print$:o})),...P("pre.mermaid",e).map(n=>Wn(n)),...P("table:not([class])",e).map(n=>Dn(n)),...P("details",e).map(n=>Fn(n,{target$:r,print$:o})),...P("[data-tabs]",e).map(n=>Nn(n,{viewport$:t,target$:r})),...P("[title]",e).filter(()=>B("content.tooltips")).map(n=>mt(n,{viewport$:t})))}function Ba(e,{alert$:t}){return t.pipe(v(r=>O(I(!0),I(!1).pipe(Ge(2e3))).pipe(m(o=>({message:r,active:o})))))}function qn(e,t){let r=R(".md-typeset",e);return C(()=>{let o=new g;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ba(e,t).pipe(w(n=>o.next(n)),_(()=>o.complete()),m(n=>$({ref:e},n)))})}var Ga=0;function Ja(e,t){document.body.append(e);let{width:r}=ce(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=cr(t),n=typeof o!="undefined"?Ne(o):I({x:0,y:0}),i=O(et(t),Ht(t)).pipe(K());return z([i,n]).pipe(m(([a,s])=>{let{x:p,y:c}=De(t),l=ce(t),f=t.closest("table");return f&&t.parentElement&&(p+=f.offsetLeft+t.parentElement.offsetLeft,c+=f.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:p-s.x+l.width/2-r/2,y:c-s.y+l.height+8}}}))}function Qn(e){let t=e.title;if(!t.length)return S;let r=`__tooltip_${Ga++}`,o=Pt(r,"inline"),n=R(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new g;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(b(({active:a})=>a)),i.pipe(_e(250),b(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Me(16,me)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ja(o,e).pipe(w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))}).pipe(Ke(se))}function Xa({viewport$:e}){if(!B("header.autohide"))return I(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Be(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),K()),o=ze("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),K(),v(n=>n?r:I(!1)),Q(!1))}function Kn(e,t){return C(()=>z([ge(e),Xa(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),K((r,o)=>r.height===o.height&&r.hidden===o.hidden),G(1))}function Yn(e,{header$:t,main$:r}){return C(()=>{let o=new g,n=o.pipe(Z(),ie(!0));o.pipe(te("active"),He(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=ue(P("[title]",e)).pipe(b(()=>B("content.tooltips")),ne(a=>Qn(a)));return r.subscribe(o),t.pipe(W(n),m(a=>$({ref:e},a)),Re(i.pipe(W(n))))})}function Za(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ce(e);return{active:o>=n}}),te("active"))}function Bn(e,t){return C(()=>{let r=new g;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?S:Za(o,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))})}function Gn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),K()),n=o.pipe(v(()=>ge(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),te("bottom"))));return z([o,n,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:p},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-p,i)-Math.max(0,c+p-s)),{offset:a-i,height:c,active:a-i<=p})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function es(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return I(...e).pipe(ne(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),G(1))}function Jn(e){let t=P("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=$t("(prefers-color-scheme: light)");return C(()=>{let i=new g;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),p=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=p.getAttribute("data-md-color-scheme"),a.color.primary=p.getAttribute("data-md-color-primary"),a.color.accent=p.getAttribute("data-md-color-accent")}for(let[s,p]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,p);for(let s=0;sa.key==="Enter"),re(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(m(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(p=>(+p).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(ve(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),es(t).pipe(W(n.pipe(Ce(1))),ct(),w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))})}function Xn(e,{progress$:t}){return C(()=>{let r=new g;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(w(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Jr=Lt(Br());function ts(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Zn({alert$:e}){Jr.default.isSupported()&&new j(t=>{new Jr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ts(R(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(w(t=>{t.trigger.focus()}),m(()=>Ee("clipboard.copied"))).subscribe(e)}function ei(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function rs(e,t){let r=new Map;for(let o of P("url",e)){let n=R("loc",o),i=[ei(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(ei(new URL(s),t))}}return r}function ur(e){return un(new URL("sitemap.xml",e)).pipe(m(t=>rs(t,new URL(e))),de(()=>I(new Map)))}function os(e,t){if(!(e.target instanceof Element))return S;let r=e.target.closest("a");if(r===null)return S;if(r.target||e.metaKey||e.ctrlKey)return S;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),I(new URL(r.href))):S}function ti(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ri(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return I(e)}function ns(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=ti(document);for(let[o,n]of ti(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Se("container");return We(P("script",r)).pipe(v(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new j(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),S}),Z(),ie(document))}function oi({location$:e,viewport$:t,progress$:r}){let o=xe();if(location.protocol==="file:")return S;let n=ur(o.base);I(document).subscribe(ri);let i=h(document.body,"click").pipe(He(n),v(([p,c])=>os(p,c)),pe()),a=h(window,"popstate").pipe(m(ye),pe());i.pipe(re(t)).subscribe(([p,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",p)}),O(i,a).subscribe(e);let s=e.pipe(te("pathname"),v(p=>fn(p,{progress$:r}).pipe(de(()=>(lt(p,!0),S)))),v(ri),v(ns),pe());return O(s.pipe(re(e,(p,c)=>c)),s.pipe(v(()=>e),te("hash")),e.pipe(K((p,c)=>p.pathname===c.pathname&&p.hash===c.hash),v(()=>i),w(()=>history.back()))).subscribe(p=>{var c,l;history.state!==null||!p.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",pn(p.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(te("offset"),_e(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),s}var ni=Lt(qr());function ii(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,ni.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function It(e){return e.type===1}function dr(e){return e.type===3}function ai(e,t){let r=yn(e);return O(I(location.protocol!=="file:"),ze("search")).pipe(Ae(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function si(e){var l;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:o,currentBaseURL:n}=e,i=(l=Xr(n))==null?void 0:l.pathname;if(i===void 0)return;let a=ss(o.pathname,i);if(a===void 0)return;let s=ps(t.keys());if(!t.has(s))return;let p=Xr(a,s);if(!p||!t.has(p.href))return;let c=Xr(a,r);if(c)return c.hash=o.hash,c.search=o.search,c}function Xr(e,t){try{return new URL(e,t)}catch(r){return}}function ss(e,t){if(e.startsWith(t))return e.slice(t.length)}function cs(e,t){let r=Math.min(e.length,t.length),o;for(o=0;oS)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:a,aliases:s})=>a===i||s.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>h(document.body,"click").pipe(b(i=>!i.metaKey&&!i.ctrlKey),re(o),v(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&n.has(s.href)){let p=s.href;return!i.target.closest(".md-version")&&n.get(p)===a?S:(i.preventDefault(),I(new URL(p)))}}return S}),v(i=>ur(i).pipe(m(a=>{var s;return(s=si({selectedVersionSitemap:a,selectedVersionBaseURL:i,currentLocation:ye(),currentBaseURL:t.base}))!=null?s:i})))))).subscribe(n=>lt(n,!0)),z([r,o]).subscribe(([n,i])=>{R(".md-header__topic").appendChild(Cn(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var s;let i=new URL(t.base),a=__md_get("__outdated",sessionStorage,i);if(a===null){a=!0;let p=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(p)||(p=[p]);e:for(let c of p)for(let l of n.aliases.concat(n.version))if(new RegExp(c,"i").test(l)){a=!1;break e}__md_set("__outdated",a,sessionStorage,i)}if(a)for(let p of ae("outdated"))p.hidden=!1})}function ls(e,{worker$:t}){let{searchParams:r}=ye();r.has("q")&&(Je("search",!0),e.value=r.get("q"),e.focus(),ze("search").pipe(Ae(i=>!i)).subscribe(()=>{let i=ye();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=et(e),n=O(t.pipe(Ae(It)),h(e,"keyup"),o).pipe(m(()=>e.value),K());return z([n,o]).pipe(m(([i,a])=>({value:i,focus:a})),G(1))}function pi(e,{worker$:t}){let r=new g,o=r.pipe(Z(),ie(!0));z([t.pipe(Ae(It)),r],(i,a)=>a).pipe(te("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(te("focus")).subscribe(({focus:i})=>{i&&Je("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=R("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),ls(e,{worker$:t}).pipe(w(i=>r.next(i)),_(()=>r.complete()),m(i=>$({ref:e},i)),G(1))}function li(e,{worker$:t,query$:r}){let o=new g,n=on(e.parentElement).pipe(b(Boolean)),i=e.parentElement,a=R(":scope > :first-child",e),s=R(":scope > :last-child",e);ze("search").subscribe(l=>s.setAttribute("role",l?"list":"presentation")),o.pipe(re(r),Wr(t.pipe(Ae(It)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:a.textContent=f.length?Ee("search.result.none"):Ee("search.result.placeholder");break;case 1:a.textContent=Ee("search.result.one");break;default:let u=sr(l.length);a.textContent=Ee("search.result.other",u)}});let p=o.pipe(w(()=>s.innerHTML=""),v(({items:l})=>O(I(...l.slice(0,10)),I(...l.slice(10)).pipe(Be(4),Dr(n),v(([f])=>f)))),m(Mn),pe());return p.subscribe(l=>s.appendChild(l)),p.pipe(ne(l=>{let f=fe("details",l);return typeof f=="undefined"?S:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(b(dr),m(({data:l})=>l)).pipe(w(l=>o.next(l)),_(()=>o.complete()),m(l=>$({ref:e},l)))}function ms(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=ye();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function mi(e,t){let r=new g,o=r.pipe(Z(),ie(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),ms(e,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))}function fi(e,{worker$:t,keyboard$:r}){let o=new g,n=Se("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(ve(se),m(()=>n.value),K());return o.pipe(He(i),m(([{suggest:s},p])=>{let c=p.split(/([\s-]+)/);if(s!=null&&s.length&&c[c.length-1]){let l=s[s.length-1];l.startsWith(c[c.length-1])&&(c[c.length-1]=l)}else c.length=0;return c})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(b(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(b(dr),m(({data:s})=>s)).pipe(w(s=>o.next(s)),_(()=>o.complete()),m(()=>({ref:e})))}function ui(e,{index$:t,keyboard$:r}){let o=xe();try{let n=ai(o.search,t),i=Se("search-query",e),a=Se("search-result",e);h(e,"click").pipe(b(({target:p})=>p instanceof Element&&!!p.closest("a"))).subscribe(()=>Je("search",!1)),r.pipe(b(({mode:p})=>p==="search")).subscribe(p=>{let c=Ie();switch(p.type){case"Enter":if(c===i){let l=new Map;for(let f of P(":first-child [href]",a)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}p.claim()}break;case"Escape":case"Tab":Je("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")i.focus();else{let l=[i,...P(":not(details) > [href], summary, details[open] [href]",a)],f=Math.max(0,(Math.max(0,l.indexOf(c))+l.length+(p.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}p.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(b(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":i.focus(),i.select(),p.claim();break}});let s=pi(i,{worker$:n});return O(s,li(a,{worker$:n,query$:s})).pipe(Re(...ae("search-share",e).map(p=>mi(p,{query$:s})),...ae("search-suggest",e).map(p=>fi(p,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ye}}function di(e,{index$:t,location$:r}){return z([t,r.pipe(Q(ye()),b(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>ii(o.config)(n.searchParams.get("h"))),m(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let p=s.textContent,c=o(p);c.length>p.length&&n.set(s,c)}for(let[s,p]of n){let{childNodes:c}=x("span",null,p);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function fs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function Zr(e,o){var n=o,{header$:t}=n,r=so(n,["header$"]);let i=R(".md-sidebar__scrollwrap",e),{y:a}=De(i);return C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=s.pipe(Me(0,me));return c.pipe(re(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ae()).subscribe(()=>{for(let l of P(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2})}}}),ue(P("label[tabindex]",e)).pipe(ne(l=>h(l,"click").pipe(ve(se),m(()=>l),W(p)))).subscribe(l=>{let f=R(`[id="${l.htmlFor}"]`);R(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),fs(e,r).pipe(w(l=>s.next(l)),_(()=>s.complete()),m(l=>$({ref:e},l)))})}function hi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return st(je(`${r}/releases/latest`).pipe(de(()=>S),m(o=>({version:o.tag_name})),Ve({})),je(r).pipe(de(()=>S),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return je(r).pipe(m(o=>({repositories:o.public_repos})),Ve({}))}}function bi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return st(je(`${r}/releases/permalink/latest`).pipe(de(()=>S),m(({tag_name:o})=>({version:o})),Ve({})),je(r).pipe(de(()=>S),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}function vi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return hi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return bi(r,o)}return S}var us;function ds(e){return us||(us=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return I(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return S}return vi(e.href).pipe(w(o=>__md_set("__source",o,sessionStorage)))}).pipe(de(()=>S),b(t=>Object.keys(t).length>0),m(t=>({facts:t})),G(1)))}function gi(e){let t=R(":scope > :last-child",e);return C(()=>{let r=new g;return r.subscribe(({facts:o})=>{t.appendChild(_n(o)),t.classList.add("md-source__repository--active")}),ds(e).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function hs(e,{viewport$:t,header$:r}){return ge(document.body).pipe(v(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),te("hidden"))}function yi(e,t){return C(()=>{let r=new g;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?I({hidden:!1}):hs(e,t)).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function bs(e,{viewport$:t,header$:r}){let o=new Map,n=P(".md-nav__link",e);for(let s of n){let p=decodeURIComponent(s.hash.substring(1)),c=fe(`[id="${p}"]`);typeof c!="undefined"&&o.set(s,c)}let i=r.pipe(te("height"),m(({height:s})=>{let p=Se("main"),c=R(":scope > :first-child",p);return s+.8*(c.offsetTop-p.offsetTop)}),pe());return ge(document.body).pipe(te("height"),v(s=>C(()=>{let p=[];return I([...o].reduce((c,[l,f])=>{for(;p.length&&o.get(p[p.length-1]).tagName>=f.tagName;)p.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return c.set([...p=[...p,l]].reverse(),u)},new Map))}).pipe(m(p=>new Map([...p].sort(([,c],[,l])=>c-l))),He(i),v(([p,c])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(s.height);for(;f.length;){let[,L]=f[0];if(L-c=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...p]]),K((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([s,p])=>({prev:s.map(([c])=>c),next:p.map(([c])=>c)})),Q({prev:[],next:[]}),Be(2,1),m(([s,p])=>s.prev.length{let i=new g,a=i.pipe(Z(),ie(!0));if(i.subscribe(({prev:s,next:p})=>{for(let[c]of p)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",c===s.length-1)}),B("toc.follow")){let s=O(t.pipe(_e(1),m(()=>{})),t.pipe(_e(250),m(()=>"smooth")));i.pipe(b(({prev:p})=>p.length>0),He(o.pipe(ve(se))),re(s)).subscribe(([[{prev:p}],c])=>{let[l]=p[p.length-1];if(l.offsetHeight){let f=cr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2,behavior:c})}}})}return B("navigation.tracking")&&t.pipe(W(a),te("offset"),_e(250),Ce(1),W(n.pipe(Ce(1))),ct({delay:250}),re(i)).subscribe(([,{prev:s}])=>{let p=ye(),c=s[s.length-1];if(c&&c.length){let[l]=c,{hash:f}=new URL(l.href);p.hash!==f&&(p.hash=f,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),bs(e,{viewport$:t,header$:r}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function vs(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:a}})=>a),Be(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return z([i,n]).pipe(m(([a,s])=>!(a&&s)),K(),W(o.pipe(Ce(1))),ie(!0),ct({delay:250}),m(a=>({hidden:a})))}function Ei(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(a),te("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),h(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),vs(e,{viewport$:t,main$:o,target$:n}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))}function wi({document$:e,viewport$:t}){e.pipe(v(()=>P(".md-ellipsis")),ne(r=>tt(r).pipe(W(e.pipe(Ce(1))),b(o=>o),m(()=>r),Te(1))),b(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,B("content.tooltips")?mt(n,{viewport$:t}).pipe(W(e.pipe(Ce(1))),_(()=>n.removeAttribute("title"))):S})).subscribe(),B("content.tooltips")&&e.pipe(v(()=>P(".md-status")),ne(r=>mt(r,{viewport$:t}))).subscribe()}function Ti({document$:e,tablet$:t}){e.pipe(v(()=>P(".md-toggle--indeterminate")),w(r=>{r.indeterminate=!0,r.checked=!1}),ne(r=>h(r,"change").pipe(Vr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),re(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function gs(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Si({document$:e}){e.pipe(v(()=>P("[data-md-scrollfix]")),w(t=>t.removeAttribute("data-md-scrollfix")),b(gs),ne(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Oi({viewport$:e,tablet$:t}){z([ze("search"),t]).pipe(m(([r,o])=>r&&!o),v(r=>I(r).pipe(Ge(r?400:100))),re(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function ys(){return location.protocol==="file:"?wt(`${new URL("search/search_index.js",eo.base)}`).pipe(m(()=>__index),G(1)):je(new URL("search/search_index.json",eo.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ot=Go(),Ft=sn(),Ot=ln(Ft),to=an(),Oe=gn(),hr=$t("(min-width: 960px)"),Mi=$t("(min-width: 1220px)"),_i=mn(),eo=xe(),Ai=document.forms.namedItem("search")?ys():Ye,ro=new g;Zn({alert$:ro});var oo=new g;B("navigation.instant")&&oi({location$:Ft,viewport$:Oe,progress$:oo}).subscribe(ot);var Li;((Li=eo.version)==null?void 0:Li.provider)==="mike"&&ci({document$:ot});O(Ft,Ot).pipe(Ge(125)).subscribe(()=>{Je("drawer",!1),Je("search",!1)});to.pipe(b(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&<(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&<(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});wi({viewport$:Oe,document$:ot});Ti({document$:ot,tablet$:hr});Si({document$:ot});Oi({viewport$:Oe,tablet$:hr});var rt=Kn(Se("header"),{viewport$:Oe}),jt=ot.pipe(m(()=>Se("main")),v(e=>Gn(e,{viewport$:Oe,header$:rt})),G(1)),xs=O(...ae("consent").map(e=>En(e,{target$:Ot})),...ae("dialog").map(e=>qn(e,{alert$:ro})),...ae("palette").map(e=>Jn(e)),...ae("progress").map(e=>Xn(e,{progress$:oo})),...ae("search").map(e=>ui(e,{index$:Ai,keyboard$:to})),...ae("source").map(e=>gi(e))),Es=C(()=>O(...ae("announce").map(e=>xn(e)),...ae("content").map(e=>zn(e,{viewport$:Oe,target$:Ot,print$:_i})),...ae("content").map(e=>B("search.highlight")?di(e,{index$:Ai,location$:Ft}):S),...ae("header").map(e=>Yn(e,{viewport$:Oe,header$:rt,main$:jt})),...ae("header-title").map(e=>Bn(e,{viewport$:Oe,header$:rt})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Nr(Mi,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt})):Nr(hr,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt}))),...ae("tabs").map(e=>yi(e,{viewport$:Oe,header$:rt})),...ae("toc").map(e=>xi(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})),...ae("top").map(e=>Ei(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})))),Ci=ot.pipe(v(()=>Es),Re(xs),G(1));Ci.subscribe();window.document$=ot;window.location$=Ft;window.target$=Ot;window.keyboard$=to;window.viewport$=Oe;window.tablet$=hr;window.screen$=Mi;window.print$=_i;window.alert$=ro;window.progress$=oo;window.component$=Ci;})(); +//# sourceMappingURL=bundle.c8b220af.min.js.map + diff --git a/assets/javascripts/bundle.c8b220af.min.js.map b/assets/javascripts/bundle.c8b220af.min.js.map new file mode 100644 index 0000000..d835be5 --- /dev/null +++ b/assets/javascripts/bundle.c8b220af.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/escape-html/index.js", "node_modules/clipboard/dist/clipboard.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/tslib/tslib.es6.mjs", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/BehaviorSubject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/QueueAction.ts", "node_modules/rxjs/src/internal/scheduler/QueueScheduler.ts", "node_modules/rxjs/src/internal/scheduler/queue.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounce.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip2/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/findurl/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*\n * Copyright (c) 2016-2025 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ viewport$, document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n};\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n */\nexport class Subscription implements SubscriptionLike {\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param value The `next` value.\n */\n next(value: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param err The `error` exception.\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as ((value: T) => void) | undefined,\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent.\n * @param subscriber The stopped subscriber.\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @param subscribe The function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @param subscribe the subscriber function to be passed to the Observable constructor\n * @return A new observable.\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @param operator the operator defining the operation to take on the observable\n * @return A new observable with the Operator applied.\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param observerOrNext Either an {@link Observer} with some or all callback methods,\n * or the `next` handler that is called for each value emitted from the subscribed Observable.\n * @param error A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param complete A handler for a terminal event resulting from successful completion.\n * @return A subscription reference to the registered handlers.\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next A handler for each value emitted by the observable.\n * @return A promise that either resolves on observable completion or\n * rejects with the handled error.\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @return This instance of the observable.\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n *\n * @return The Observable result of all the operators having been called\n * in the order they were passed in.\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return Observable that this Subject casts to.\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { Subject } from './Subject';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\n\n/**\n * A variant of Subject that requires an initial value and emits its current\n * value whenever it is subscribed to.\n */\nexport class BehaviorSubject extends Subject {\n constructor(private _value: T) {\n super();\n }\n\n get value(): T {\n return this.getValue();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n const subscription = super._subscribe(subscriber);\n !subscription.closed && subscriber.next(this._value);\n return subscription;\n }\n\n getValue(): T {\n const { hasError, thrownError, _value } = this;\n if (hasError) {\n throw thrownError;\n }\n this._throwIfClosed();\n return _value;\n }\n\n next(value: T): void {\n super.next((this._value = value));\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param _bufferSize The size of the buffer to replay on subscription\n * @param _windowTime The amount of time the buffered items will stay buffered\n * @param _timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param state Some contextual data that the `work` function uses when called by the\n * Scheduler.\n * @param delay Time to wait before executing the work, where the time unit is implicit\n * and defined by the Scheduler.\n * @return A subscription in order to be able to unsubscribe the scheduled work.\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param work A function representing a task, or some unit of work to be\n * executed by the Scheduler.\n * @param delay Time to wait before executing the work, where the time unit is\n * implicit and defined by the Scheduler itself.\n * @param state Some contextual data that the `work` function uses when called\n * by the Scheduler.\n * @return A subscription in order to be able to unsubscribe the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { Subscription } from '../Subscription';\nimport { QueueScheduler } from './QueueScheduler';\nimport { SchedulerAction } from '../types';\nimport { TimerHandle } from './timerHandle';\n\nexport class QueueAction extends AsyncAction {\n constructor(protected scheduler: QueueScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (delay > 0) {\n return super.schedule(state, delay);\n }\n this.delay = delay;\n this.state = state;\n this.scheduler.flush(this);\n return this;\n }\n\n public execute(state: T, delay: number): any {\n return delay > 0 || this.closed ? super.execute(state, delay) : this._execute(state, delay);\n }\n\n protected requestAsyncId(scheduler: QueueScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n\n if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n\n // Otherwise flush the scheduler starting with this action.\n scheduler.flush(this);\n\n // HACK: In the past, this was returning `void`. However, `void` isn't a valid\n // `TimerHandle`, and generally the return value here isn't really used. So the\n // compromise is to return `0` which is both \"falsy\" and a valid `TimerHandle`,\n // as opposed to refactoring every other instanceo of `requestAsyncId`.\n return 0;\n }\n}\n", "import { AsyncScheduler } from './AsyncScheduler';\n\nexport class QueueScheduler extends AsyncScheduler {\n}\n", "import { QueueAction } from './QueueAction';\nimport { QueueScheduler } from './QueueScheduler';\n\n/**\n *\n * Queue Scheduler\n *\n * Put every next task on a queue, instead of executing it immediately\n *\n * `queue` scheduler, when used with delay, behaves the same as {@link asyncScheduler} scheduler.\n *\n * When used without delay, it schedules given task synchronously - executes it right when\n * it is scheduled. However when called recursively, that is when inside the scheduled task,\n * another task is scheduled with queue scheduler, instead of executing immediately as well,\n * that task will be put on a queue and wait for current one to finish.\n *\n * This means that when you execute task with `queue` scheduler, you are sure it will end\n * before any other task scheduled with that scheduler will start.\n *\n * ## Examples\n * Schedule recursively first, then do something\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(() => {\n * queueScheduler.schedule(() => console.log('second')); // will not happen now, but will be put on a queue\n *\n * console.log('first');\n * });\n *\n * // Logs:\n * // \"first\"\n * // \"second\"\n * ```\n *\n * Reschedule itself recursively\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(function(state) {\n * if (state !== 0) {\n * console.log('before', state);\n * this.schedule(state - 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * console.log('after', state);\n * }\n * }, 0, 3);\n *\n * // In scheduler that runs recursively, you would expect:\n * // \"before\", 3\n * // \"before\", 2\n * // \"before\", 1\n * // \"after\", 1\n * // \"after\", 2\n * // \"after\", 3\n *\n * // But with queue it logs:\n * // \"before\", 3\n * // \"after\", 3\n * // \"before\", 2\n * // \"after\", 2\n * // \"before\", 1\n * // \"after\", 1\n * ```\n */\n\nexport const queueScheduler = new QueueScheduler(QueueAction);\n\n/**\n * @deprecated Renamed to {@link queueScheduler}. Will be removed in v8.\n */\nexport const queue = queueScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && id === scheduler._scheduled && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n let flushId;\n if (action) {\n flushId = action.id;\n } else {\n flushId = this._scheduled;\n this._scheduled = undefined;\n }\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an - -## How to Use This Site - -- Lectures can be found by topics at the navigation bar. The sub topics can be found at those pages. Search bar is also available for finding pages by terms. -- In each lecture related problems and training sets from [algoleague.com](https://algoleague.com) are mentioned. Practicing those is highly recommended. - -## How to Contribute - -In order to contribute (adding new lecture, fixing any type of errors) below steps should be followed: - -1. Create an issue and briefly explain the purpose of your contribution. -2. Fork the repository with your personal account and apply your changes. -3. Create a pull request to master branch and add the link of pull request to issue. -4. After reviewing your pull request and discussion, your pull request will be merged. Thank you for your contribution! diff --git a/docs/introduction/index.md b/docs/introduction/index.md deleted file mode 100644 index 64ed11d..0000000 --- a/docs/introduction/index.md +++ /dev/null @@ -1,525 +0,0 @@ ---- -title: Introduction ---- - -**Editor:** Muhammed Burak Buğrul - -**Reviewers:** Kadir Emre Oto & Yusuf Hakan Kalaycı - -## Introduction - -First of all, this is an intensive algorithm programme prepared by inzva, which includes lectures, contests, problem-solvings and a variety of practises. "Competitive Programming" term will be mentioned frequently in this programme, especially for it's community, help in progress in algorithms and data structures etc. - -Just for a quick cover up we will have a look at what happens when you compile and run a program, basic data types and functions. After that, we will examine C++ Standard Template Library(STL), time complexity and memory space. - -## Command Line - -A lot of people don't use command line if they can use an alternative. There are powerful IDEs (Integrated Development Environments) and they really make programming easier in some aspects. However, knowing how to use command line is important, especially for competitive programming. Firstly, it gives a low level knowledge and full control; secondly, every computer and environment has command line interface. - -In this document, you will find only a basic introduction to the command line, which is no more than the basic usage of a file system, compiler, and programs. - -There are a lot of differences between command line of Windows and Linux. But the differences between those of Mac and Linux are less. - -### Linux and Mac - -Mac users can use the built-in Terminal. You can find it by searching from Spotlight. Linux users can use gnome-terminal or any other installed one. Again, you can find them by using the built-in search tab. - -Some basic commands: - -- `ls` list files in current directory. Usage: `ls` -- `cd` change directory. Usage: `cd ~/Desktop` -- `mkdir` make a new directory. Usage: `mkdir directory_name` -- `mv` move command (cut). Usage: `mv source_path destination_path` -- `cp` copy command. Usage: `cp source_path destination_path` -- `rm` remove command. Usage: `rm file_path` - -You can read more about the unix command line at: [http://linuxcommand.org](http://linuxcommand.org) - -## Compiling and Executing Programs - -### G++ - -G++ is installed in Linux environments but in Mac, you should install Xcode first. - -You can compile your cpp souce file by typing `g++ source.cpp`. Default output of this command is `a.out`. - -### Running Executable Files - -For Linux and Mac, the command to run a program is `./program_name`. If you use default `g++` command, the name of your program will be `a.out`, so you should type `./a.out` in order to run it. - -### Closing a Program - -When you want to kill a program in running step, you can simply hit *Control + C*. - -When you want to suspend a program in running step, you can simply hit *Control + Z*. - -When you want to register EOF on standart input, you can simply hit *Control + D*. - -### Input/Output Redirection - -You can redirect input and output streams of a program by using command line and it is surprisingly easy. - -### Saving Output to a File - -The only thing you need is `>` symbol. Just add it at the end of your run command with the output file name: `./a.out > output.txt` - -**Note:** This redirection process creates `output.txt` if it doesn't exist; otherwise deletes all content in it, then writes into it. If you want to use `>` in appending mode you should use `>>` instead. - -### Reading Input from a File - -It is almost the same as output file redirection. The symbol is `<` now. Usage: `./a.out < input.txt` - -**This will make your job easier than copying and pasting input to test your program, especially in the contests.** - -### Using Both at the Same Time - -One of the wonderful things about these redirections is that they can be used at the same time. You can simply add both to the end of your run command: `./a.out < input.txt > output.txt` - -### pipe - -Sometimes, you may want to redirect the output of a program to another program as input. You can use the `|` symbol for this. Usage: `./program1 | ./program2` - -### diff - -As the name denotes, it can check two files line by line if they are the same or not. If not, it outputs different lines. Usage: `diff file1.txt file2.txt` - -It is very useful for comparing output of brute force solution and real solution. - -## Structs and Classes - -In almost every programming language, you can define your own data type. C++ has structs, classes; Python has dictionaries, classes etc. You can think of them as packets that store more than one different data and implement functions at the simplest level. They have a lot more abilities than these two (You can check OOP out). - -Let us examine a fraction struct written in C++. - -We need to store two values for a fraction, numerator and denominator. - -```c++ linenums="1" -struct Fraction { - int numerator, denominator; -}; -``` - -This is the simplest definition of a struct. Fraction struct contains two `int` variables. We call them members. So, Fraction struct has two members called numerator and denominator. - -```c++ linenums="1" -#include - -struct Fraction { - int numerator, denominator; -}; - -Fraction bigFraction(Fraction a, Fraction b) { - - if( a.numerator * b.denominator > a.denominator * b.numerator ) - return a; - - return b; -} - -int main() { - // Create two Fractions in order to compare them - Fraction a, b; - - a.numerator = 15; - a.denominator = 20; - - b.numerator = 12; - b.denominator = 18; - - // Create a new Fraction in order to store biggest of Fraction a and Fraction b. - fraction biggest = bigFraction(a, b); - - printf("The biggest fraction is %d / %d\n", biggest.numerator, biggest.denominator); - return 0; -} -``` - -Let us do the same in Python3: - -```py linenums="1" -class Fraction: - - def __init__(self, numerator, denominator): - self.numerator, self.denominator = numerator, denominator - -def bigFraction(a, b): - - if a.numerator * b.denominator > a.denominator * b.numerator: - return a - - return b - -a, b = Fraction(15, 20), Fraction(12, 18) # Create two Fractions in order to compare them -biggest = bigFraction(a, b) - -print(biggest.numerator, biggest.denominator) -``` - -In the sample codes above, `a`, `b` and `biggest` are called **objects** of `Fraction`. Also, the word **instance** can be used instead of object. - -### The Arrow Operator (C++) -Sometimes, usage of struct can change in C++. When you have a pointer to a struct, you should use `->` to access its members instead of `.` operator. If you still want to use `.` operator, you should do in this way: `(*ptr).member`. But arrow operator is simpler: `ptr->member`. - -## Big O Notation - -When dealing with algorithms or coming up with a solution, we need to calculate how fast our algorithm or solution is. We can calculate this in terms of number of operations. Big $\mathcal{O}$ notation moves in exactly at this point. Big $\mathcal{O}$ notation gives an upper limit to these number of operations. The formal definition of Big $\mathcal{O}$ is [1]. - -Let $f$ be a real or complex valued function and $g$ a real valued function, both defined on some unbounded subset of the real positive numbers, such that $g(x)$ is strictly positive for all large enough values of $x$. One writes: - -$$f(x) = \mathcal{O}{(g(x))} \ as\ x \rightarrow \infty$$ - -If and only if for all sufficiently large values of x, the absolute value of $f(x)$ is at most a positive constant multiple of $g(x)$. That is, $f(x)$ = $\mathcal{O}{(g(x))}$ if and only if there exists a positive real number $M$ and a real number $x_0$ such that: - -$$|f(x)| \leq Mg(x)\ for \ all\ x\ such\ that\ x_0 \leq x$$ - -In many contexts, the assumption that we are interested in the growth rate as the variable $x$ goes to infinity is left unstated, and one writes more simply that: - -$$f(x) = \mathcal{O}(g(x))$$ - -Almost every case for competitive programming, basic understanding of Big $\mathcal{O}$ notation is enough to decide whether to implement a solution or not. - -**Note:** Big $\mathcal{O}$ notation can be used for calculating both the run time complexity and the memory space used. - -## Recursion - -*Recursion* occurs when functions repeat themselves in order to create repeated applications or solve a problem by handling smaller situations first. There are thousands of examples in mathematics. One of the simple ones is *factorial* of $n$. It can be shown by $n!$ in mathematics and it gives the product of all positive integers from $1$ to $n$, for example, $4! = 1\cdot 2\cdot 3\cdot 4 = 24$. If we write factorial in a mathematical way, it will be: - -$$ -\begin{align*} - f(n) &= \begin{cases} - 1 & \text{if $n = 0$\,\, } \\ - n \cdot f(n - 1) & \text{if $n > 0$\,\,} - \end{cases} -\end{align*} -$$ - -The reason why we didn't simply write it as $f(n) = n \cdot f(n-1)$ is that it doesn't give sufficient information about function. We should know where to end the function calls, otherwise it can call itself infinitely. Ending condition is $n = 0$ here. We call it *base case*. Every recursive function needs at least one base case. - -So if we write every step of $f(4)$, it will be: - -$$ -\begin{align*} - 4! - &= 4\cdot f(3) && \text{recursive step} \\ - &= 4\cdot 3\cdot f(2) && \text{recursive step} \\ - &= 4\cdot 3\cdot 2\cdot f(1) && \text{recursive step} \\ - &= 4\cdot 3\cdot 2\cdot 1\cdot f(0) && \text{recursive step} \\ - &= 4\cdot 3\cdot 2\cdot 1\cdot 1 && \text{base case} \\ - &= 24 && \text{arithmetic} -\end{align*} -$$ - -Basically, we can apply this recursive logic into programming: - -```c++ linenums="1" -int factorial(int n) { - int result = 1; - for(int i = 1; i <= n; i++) - res *= i; - return result; -} -``` - -We can say a function is a recursive if it calls itself. Let us change this iterative factorial function into a recursive one. When you imagine how the recursive code will look like, you will notice it will look like the mathematical one: - -```c++ linenums="1" -int factorial(int n) { - if(n == 0) - return 1; - return n * factorial(n - 1); -} -``` - -Note that we didn't forget to put our base case into the recursive function implementation. - -### Time Complexity - -In case above, it can be seen that both recursive and iterative implementations of factorial function runs in $\mathcal{O}{(n)}$ time. But this equality doesn't occur always. Let us examine fibonacci function, it is mathematically defines as: - -$$ -\begin{align*} - f(n) &= \begin{cases} - 1 & \text{if $n = 0$ or $n = 1$\,\, } \\ - f(n - 1) + f(n - 2) & \text{if $n > 1$\,\,} - \end{cases} -\end{align*} -$$ - -We can implement this function with just one for loop: - -```c++ linenums="1" -int fibonacci(int n) { - int result = 1, previous = 1; - for (int i = 2; i <= n; i++) { - int tmp = result; - result += previous; - previous = tmp; - } - return result; -} -``` - -Again, we can implement recursive one according to the mathematical formula: - -```c++ linenums="1" -int fibonacci(int n) { - if( n == 0 || n == 1 ) - return 1; - return fibonacci(n - 1) + fibonacci(n - 2); -} -``` - -Let us calculate time complexity of iterative one. There are three basic operations inside a for loop that repeats $n-2$ times. So time complexity is $\mathcal{O}(n)$. But what about the recursive one? Let us examine its recursion tree(diagram of function calls) for $n = 5$ on [visualgo](https://visualgo.net/en/recursion). - -$f$ function called more than one for some values of n. Actually in every level, number of function calls doubles. So time complexity of the recursive implementation is $\mathcal{O}{(2^n)}$. It is far away worse than the iterative one. Recursive one can be optimized by techniques like memoization, but it is another topic to learn in further weeks. - -### Mutual Recursion - -Mutual recursion occurs when functions call each other. For example function `f` calls another function `g`, which also somehow calls `f` again. - -**Note:** When using mutual recursions in C++, don't forget to declare one of the functions so that the other function can know first one from its' prototype. - -**Note 2:** You can chain more than two functions and it will be still a mutual recursion. - -### Enumeration and Brute-Force - -**Enumeration** is numbering method on a set. - -For example, permutation is one of enumeration techniques. First permutation of numbers in range $1$ and $n$ is: - -$$1, 2, 3... n-1, n$$ - -And second one is: - -$$1, 2, 3... n, n-1$$ - -Finally, the last one is: - -$$n, n-1... 3, 2, 1$$ - -Additionally, we can try to enumerate all possible distributions of $n$ elements into 3 different sets. An example of a distribution of 5 elements can be represented as: - -$$1, 1, 2, 1, 3$$ - -In this distribution the first, the second and the fourth elements goes into the first set; third element goes into second set and the last element goes into the third set. - -Enumerations can be done with recursive functions easily. We will provide example implementations of 3-set one. But before examining recursive implementation, let us try to implement iterative one: - -```c++ linenums="1" -#include - -int main(){ - - for( int i=1 ; i<=3 ; i++ ) - for( int j=1 ; j<=3 ; j++ ) - for( int k=1 ; k<=3 ; k++ ) - for( int l=1 ; l<=3 ; l++ ) - for( int m=1 ; m<=3 ; m++ ) - printf("%d %d %d %d %d\n", i, j, k, l, m); - - return 0; -} -``` - -It will print all possible distributions of 5 elements into 3 sets. But what if we had 6 elements? Yes, we should have added another for loop. What if we had $n$ elements? We can not add infinite number of for loops. But we can apply same logic with recursive functions easily: - -```c++ linenums="1" -#include - -int ar[100]; - -void enumerate( int element, int n ){ - - if( element > n ){ // Base case - - for( int i=1 ; i<=n ; i++ ) - printf("%d ", ar[i]); - - printf("\n"); - return; - } - - for( int i=1 ; i<=3 ; i++ ){ - ar[element] = i; - enumerate(element + 1, n); - } -} - -int main(){ - enumerate(1, 5); - return 0; -} -``` - -**Brute-Force** is trying all cases in order to achieve something(searching best, shortest, cheapest etc.). - -One of the simplest examples of brute-forces approaches is primality checking. We know that for a prime $P$ there is no positive integer in range $[2, P-1]$ that evenly divides $P$. We can simply check all integers in this range to decide if it is prime: - -```c++ linenums="1" -bool isPrime(int N) { - for( int i=2 ; i - -using namespace std; - -int main(){ - - pair p(1, 2); - pair p2; - - p2.first = 3; - p2.second = "Hey there!"; - - pair, string> nested; - - nested.first = p2; - nested.second = "This is a nested one"; - - cout << "Info of p -> " << p.first << " " << p.second << endl; - cout << "Info of p2 -> " << p2.first << " " << p2.second << endl; - cout << "Info of nested -> " << nested.first.first << " " << nested.first.second - << " " << nested.second << endl; - - return 0; -} -``` - -**Python:** You can simply create a tuple or an array: - -```py linenums="1" -p = (1, 2) -p2 = [1, "Hey there!"] -nested = ((3, "inner?"), "outer", "this is a tuple you can add more") - -p2[0] = 3 -# nested[0] = "don't" # In python you can't change tuples, but you can change arrays - -print(p, p2, nested) -``` - -### Vectors - -**C++:** When using array, we should decide its size. What if we don't have to do this, what if we could add elements into it without considering the current size? Well, all these ideas take us to vectors. - -C++ has this structure. Its name is vector. It is a dynamic array but you don't have to think about its size. You can simply add elements into it. Like pairs, you can use it with any type (int, double, another vector, your struct/class etc.). Usage of a vector is very similar to classic array: - -```c++ linenums="1" -#include -#include - -using namespace std; - -int main(){ - - vector ar; - - for( int i=0 ; i<10 ; i++ ) - ar.push_back(i); - - for( int i=0 ; i<(int)ar.size() ; i++ ) - cout << ar[i] << " "; - - cout << endl; - return 0; -} -``` - -**Python:** Python lists already behave like vectors: - -```py linenums="1" -ar = [] - -for i in range(10): - ar.append(i) - -print(ar) -``` - -### Stacks, Queues, and Deques - -**C++:** They are no different than stack, queue and deque we already know. It provides the implementation, you can simply include the libraries and use them. See [queue](http://www.cplusplus.com/reference/queue/queue/), [stack](http://www.cplusplus.com/reference/stack/stack/), [deque](http://www.cplusplus.com/reference/deque/deque/). - -### Priority Queues -It is basically a built-in heap structure. You can add an element in $\mathcal{O}(logN)$ time, get the first item in $O(logN)$ time. The first item will be decided according to your choice of priority. This priority can be magnitude of value, enterence time etc. - -**C++:** The different thing for priority queue is you should add `#include `, not ``. You can find samples [here](http://www.cplusplus.com/reference/queue/priority_queue/). Again, you can define a priority queue with any type you want. - -**Note:** Default `priority_queue` prioritizes elements by highest value first. [Here](https://en.cppreference.com/w/cpp/container/priority_queue) is three ways of defining priority. - -**Python:** You can use [heapq](https://docs.python.org/2/library/heapq.html) in python. - -### Sets and Maps - -**C++:** Now that we mentioned binary trees (heap above), we can continue on built-in self balanced binary trees. Sets are key collections, and maps are key-value collections. Sets are useful when you want to add/remove elements in $\mathcal{O}(logN)$ time and also check existence of an item(key) in $O(logN)$ time. Maps basically do the same but you can change value associated to a key without changing the position of the key in the tree. You can check c++ references for [set](http://www.cplusplus.com/reference/set/set/) and [map](http://www.cplusplus.com/reference/map/map/map/). You can define them with any type you want. If you want to use them with your own struct/class, you must implement a compare function. - -**Python:** You can use dictionaries for [map](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) and [sets](https://docs.python.org/3/tutorial/datastructures.html#sets) for set in python without importing any other libraries. - -### Iterators - -**C++:** You can use [iterators](http://www.cplusplus.com/reference/iterator/) for every built-in data structure in C++ for pointing their objects. - -**Python:** You can iterate through any iterable in python by using **in**. You can check [this](https://wiki.python.org/moin/ForLoop) example. - -### Sorting - -**C++:** In almost every language, there is a built-in [sort](http://www.cplusplus.com/reference/algorithm/sort/) function. C++ has one as well. It runs in $\mathcal{O}(N log N)$ time. You can pass your own compare function into sort function of C++. - -**Python:** You can use [sort](https://docs.python.org/3/howto/sorting.html) function for any list or list like collection in order to sort them or if you don't want to change the original collection, you can use `sorted()` function instead. You can pass your own compare function into sort function of python by using key variable. - -## Suggested Readings - -### C++ - -- **next_permutation:** [Link](http://www.cplusplus.com/reference/algorithm/next_permutation/) -- **STL document:** [Link](http://www.cplusplus.com/reference/stl/) -- **binary_search:** [Link](http://www.cplusplus.com/reference/algorithm/binary_search/) -- **upper_bound:** [Link](http://www.cplusplus.com/reference/algorithm/upper_bound/) -- **lower_bound:** [Link](http://www.cplusplus.com/reference/algorithm/lower_bound/) -- **reverse:** [Link](http://www.cplusplus.com/reference/algorithm/reverse/) -- **fill:** [Link](http://www.cplusplus.com/reference/algorithm/fill/) -- **count:** [Link](http://www.cplusplus.com/reference/algorithm/count/) - -### Python - -- **bisect:** [Link](https://docs.python.org/3.0/library/bisect.html) -- **collections:** [Link](https://docs.python.org/3/library/collections.html) -- **built-in functions:** [Link](https://docs.python.org/3/library/functions.html) -- **lambda:** [Link](https://www.w3schools.com/python/python_lambda.asp) - -## References - -1. Landau, Edmund (1909). Handbuch der Lehre von der Verteilung der Primzahlen [Handbook on the theory of the distribution of the primes] (in German). Leipzig: B. G. Teubner. p. 31. \ No newline at end of file diff --git a/dynamic-programming/bitmask-dp/index.html b/dynamic-programming/bitmask-dp/index.html new file mode 100644 index 0000000..7bdc0cd --- /dev/null +++ b/dynamic-programming/bitmask-dp/index.html @@ -0,0 +1,766 @@ + + + + + + + + + + + + + + + + + + + + + Bitmask DP - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Bitmask DP + +

+ +
+ + +

What is Bitmask?

+

Let’s say that we have a set of objects. How can we represent a subset of this set? One way is using a map and mapping each object with a Boolean value indicating whether the object is picked. Another way is, if the objects can be indexed by integers, we can use a Boolean array. However, this can be slow due to the operations of the map and array structures. If the size of the set is not too large (less than 64), a bitmask is much more useful and convenient.

+

An integer is a sequence of bits. Thus, we can use integers to represent a small set of Boolean values. We can perform all the set operations using bit operations. These bit operations are faster than map and array operations, and the time difference may be significant in some problems.

+

In a bitmask, the \( i \)-th bit from the right represents the \( i \)-th object. For example, let \( A = \{1, 2, 3, 4, 5\} \), we can represent \( B = \{1, 2, 4\} \) with the 11 (01011) bitmask.

+
+

Bitmask Operations

+
    +
  • +

    Add the \( i \)-th object to the subset:
    + Set the \( i \)-th bit to 1:
    +\( \text{mask } = \text{mask } | \text{ } (1 << i) \)

    +
  • +
  • +

    Remove the \( i \)-th object from the subset:
    + Set the \( i \)-th bit to 0:
    +\( \text{mask } = \text{mask } \& \sim (1 << i) \)

    +
  • +
  • +

    Check whether the \( i \)-th object is in the subset:
    + Check if the \( i \)-th bit is set:
    +\( \text{mask } \& \text{ } (1 << i) \).
    + If the expression is equal to 1, the \( i \)-th object is in the subset. If the expression is equal to 0, the \( i \)-th object is not in the subset.

    +
  • +
  • +

    Toggle the existence of the \( i \)-th object:
    + XOR the \( i \)-th bit with 1, turning 1 into 0 and 0 into 1:
    +\( \text{mask} = \text{mask}\) ^ \( (1 << i) \)

    +
  • +
  • +

    Count the number of objects in the subset:
    + Use a built-in function to count the number of 1’s in an integer variable:
    +__builtin_popcount(mask) for integers or __builtin_popcountll(mask) for long longs.

    +
  • +
+
+

Iterating Over Subsets

+
    +
  • +

    Iterate through all subsets of a set with size \( n \):
    +\( \text{for (int x = 0; x < (1 << n); ++x)} \)

    +
  • +
  • +

    Iterate through all subsets of a subset with the mask \( y \):
    +\( \text{for (int x = y; x > 0; x = (y \& (x − 1)))} \)

    +
  • +
+
+

Task Assignment Problem

+

There are \( N \) people and \( N \) tasks, and each task is going to be allocated to a single person. We are also given a matrix cost of size \( N \times N \), where cost[i][j] denotes how much a person is going to charge for a task. We need to assign each task to a person such that the total cost is minimized. Note that each task is allocated to only one person, and each person is allocated only one task.

+

Naive Approach:

+

Try \( N! \) possible assignments.
+Time complexity: \( O(N!) \).

+

DP Approach:

+

For every possible subset, find the new subsets that can be generated from it and update the DP array. Here, we use bitmasking to represent subsets and iterate over them.
+Time complexity: \( O(2^N \times N) \).

+

Note: The Hungarian Algorithm solves this problem in \( O(N^3) \) time complexity.

+

Solution code for DP approach:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
for (int mask = 0; mask < (1 << n); ++mask)
+{
+    for (int j = 0; j < n; ++j)
+    {
+        if((mask & (1 << j)) == 0) // jth task not assigned
+        {
+            dp[mask | (1 << j)] = min(dp[mask | (1 << j)], dp[mask] + cost[__builtin_popcount(mask)][j])
+        }
+    }
+}
+// after this operation our answer stored in dp[(1 << N) - 1]
+
+
+

References

+ + + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/common-dp-problems/index.html b/dynamic-programming/common-dp-problems/index.html new file mode 100644 index 0000000..a48da50 --- /dev/null +++ b/dynamic-programming/common-dp-problems/index.html @@ -0,0 +1,1063 @@ + + + + + + + + + + + + + + + + + + + + + Common Dynamic Programming Problems - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + +

+ + Common Dynamic Programming Problems + +

+ +
+ + +

Coin Problem

+

As discussed earlier, the Greedy approach doesn’t work all the time for the coin problem. For example, if the coins are {4, 3, 1} and the target sum is \(6\), the greedy algorithm produces the solution \(4+1+1\), while the optimal solution is \(3+3\). This is where Dynamic Programming (DP) helps.

+

Solution

+

Approach:

+
    +
  1. If \( V == 0 \), then 0 coins are required.
  2. +
  3. If \( V > 0 \), compute \( \text{minCoins}(coins[0..m-1], V) = \min \{ 1 + \text{minCoins}(V - \text{coin}[i]) \} \) for all \( i \) where \( \text{coin}[i] \leq V \).
  4. +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
def minCoins(coins, target):
+    # base case
+    if (V == 0):
+        return 0
+
+    n = len(coins)
+    # Initialize result
+    res = sys.maxsize
+
+    # Try every coin that has smaller value than V
+    for i in range(0, n):
+        if (coins[i] <= target):
+            sub_res = minCoins(coins, target-coins[i])
+
+    # Check for INT_MAX to avoid overflow and see if
+    # result can minimized
+    if (sub_res != sys.maxsize and sub_res + 1 < res):
+        res = sub_res + 1
+
+    return res
+
+

Knapsack Problem

+

We are given the weights and values of \( n \) items, and we are to put these items in a knapsack of capacity \( W \) to get the maximum total value. In other words, we are given two integer arrays val[0..n-1] and wt[0..n-1], which represent the values and weights associated with \( n \) items. We are also given an integer \( W \), which represents the knapsack's capacity. Our goal is to find out the maximum value subset of val[] such that the sum of the weights of this subset is smaller than or equal to \( W \). We cannot break an item; we must either pick the complete item or leave it.

+

Approach:

+

There are two cases for every item: +1. The item is included in the optimal subset. +2. The item is not included in the optimal subset.

+

The maximum value that can be obtained from \( n \) items is the maximum of the following two values: +1. Maximum value obtained by \( n-1 \) items and \( W \) weight (excluding the \( n \)-th item). +2. Value of the \( n \)-th item plus the maximum value obtained by \( n-1 \) items and \( W - \text{weight of the } n \)-th item (including the \( n \)-th item).

+

If the weight of the \( n \)-th item is greater than \( W \), then the \( n \)-th item cannot be included, and case 1 is the only possibility.

+

For example:

+
    +
  • Knapsack max weight: \( W = 8 \) units
  • +
  • Weight of items: \( \text{wt} = \{3, 1, 4, 5\} \)
  • +
  • Values of items: \( \text{val} = \{10, 40, 30, 50\} \)
  • +
  • Total items: \( n = 4 \)
  • +
+

The sum \( 8 \) is possible with two combinations: {3, 5} with a total value of 60, and {1, 3, 4} with a total value of 80. However, a better solution is {1, 5}, which has a total weight of 6 and a total value of 90.

+

Recursive Solution

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
def knapSack(W , wt , val , n):
+
+    # Base Case
+    if (n == 0 or W == 0):
+        return 0
+
+    # If weight of the nth item is more than Knapsack of capacity
+    # W, then this item cannot be included in the optimal solution
+    if (wt[n-1] > W):
+        return knapSack(W, wt, val, n - 1)
+
+    # return the maximum of two cases:
+    # (1) nth item included
+    # (2) not included
+    else:
+        return max(val[n-1] + knapSack(W - wt[n - 1], wt, val, n - 1), knapSack(W, wt, val, n - 1))
+
+

Dynamic Programming Solution

+

It should be noted that the above function computes the same subproblems again and again. Time complexity of this naive recursive solution is exponential \(2^n\). +Since suproblems are evaluated again, this problem has Overlapping Subproblems property. Like other typical Dynamic Programming(DP) problems, recomputations of same subproblems can be avoided by constructing a temporary array \(K[][]\) in bottom up manner. Following is Dynamic Programming based implementation.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
def knapSack(W, wt, val, n):
+    K = [[0 for x in range(W + 1)] for x in range(n + 1)]
+
+    # Build table K[][] in bottom up manner
+    for (i in range(n + 1)):
+        for (w in range(W + 1)):
+            if (i == 0 or w == 0):
+                K[i][w] = 0
+            elif (wt[i - 1] <= w):
+                K[i][w] = max(val[i - 1] + K[i - 1][w - wt[i - 1]], K[i - 1][w])
+            else:
+                K[i][w] = K[i - 1][w]
+
+    return K[n][W]
+
+

Longest Common Substring (LCS) Problem

+

We are given two strings \( X \) and \( Y \), and our task is to find the length of the longest common substring.

+

Sample Case:

+
    +
  • Input: \( X = "inzvahackerspace" \), \( Y = "spoilerspoiler" \)
  • +
  • Output: 4
  • +
+

The longest common substring is "ersp" and is of length 4.

+

Approach:

+

Let \( m \) and \( n \) be the lengths of the first and second strings, respectively. A simple solution is to consider all substrings of the first string one by one and check if they are substrings of the second string. Keep track of the maximum-length substring. There will be \( O(m^2) \) substrings, and checking if one is a substring of the other will take \( O(n) \) time. Thus, the overall time complexity is \( O(n \cdot m^2) \).

+

Dynamic programming can reduce this to \( O(m \cdot n) \). The idea is to find the length of the longest common suffix for all substrings of both strings and store these lengths in a table. The longest common suffix has the following property:

+

[ +LCSuff(X, Y, m, n) = LCSuff(X, Y, m-1, n-1) + 1 \text{ if } X[m-1] = Y[n-1] +] +Otherwise, \( LCSuff(X, Y, m, n) = 0 \).

+

The maximum length of the Longest Common Suffix is the Longest Common Substring.

+

DP - Iterative

+
 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
+26
+27
+28
+29
+30
+31
+32
+33
def LCSubStr(X, Y):
+    m = len(X)
+    n = len(Y)
+
+    # Create a table to store lengths of
+    # longest common suffixes of substrings.
+    # Note that LCSuff[i][j] contains the
+    # length of longest common suffix of
+    # X[0...i−1] and Y[0...j−1]. The first
+    # row and first column entries have no
+    # logical meaning, they are used only
+    # for simplicity of the program.
+
+    # LCSuff is the table with zero
+    # value initially in each cell
+    LCSuff = [[0 for k in range(n+1)] for l in range(m + 1)]
+
+    # To store the length of
+    # longest common substring
+    result = 0
+
+    # Following steps to build
+    # LCSuff[m+1][n+1] in bottom up fashion
+    for (i in range(m + 1)):
+        for (j in range(n + 1)):
+    if (i == 0 or j == 0):
+                LCSuff[i][j] = 0
+            elif (X[i - 1] == Y[j - 1]):
+                LCSuff[i][j] = LCSuff[i - 1][j - 1] + 1
+                result = max(result, LCSuff[i][j])
+            else:
+                LCSuff[i][j] = 0
+    return result
+
+

DP - Recursive

+
1
+2
+3
+4
+5
+6
+7
+8
+9
def lcs(int i, int j, int count):
+    if (i == 0 or j == 0):
+        return count
+
+    if (X[i - 1] == Y[j - 1]):
+        count = lcs(i - 1, j - 1, count + 1)
+
+    count = max(count, max(lcs(i, j - 1, 0), lcs(i - 1, j, 0)))
+    return count
+
+

Longest Increasing Subsequence (LIS) Problem

+

The Longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

+

For example, given the array \([0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]\), the longest increasing subsequence has a length of 6, and it is {0, 2, 6, 9, 11, 15}.

+

Solution

+

A naive, brute-force approach is to generate every possible subsequence, check for monotonicity, and keep track of the longest one. However, this is prohibitively expensive, as generating each subsequence takes \( O(2^N) \) time.

+

Instead, we can use recursion to solve this problem and then optimize it with dynamic programming. We assume that we have a function that gives us the length of the longest increasing subsequence up to a certain index.

+

The base cases are: +- The empty list, which returns 0. +- A list with one element, which returns 1.

+

For every index \( i \), calculate the longest increasing subsequence up to that point. The result can only be extended with the last element if the last element is greater than \( \text{arr}[i] \), as otherwise, the sequence wouldn’t be increasing.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
def longest_increasing_subsequence(arr):
+    if (not arr):
+        return 0
+    if (len(arr) == 1):
+        return 1
+
+    max_ending_here = 0
+    for (i in range(len(arr))):
+        ending_at_i = longest_increasing_subsequence(arr[:i])
+        if (arr[-1] > arr[i - 1] and ending_at_i + 1 > max_ending_here):
+            max_ending_here = ending_at_i + 1
+    return max_ending_here
+
+

This is really slow due to repeated subcomputations (exponential in time). So, let’s use dynamic +programming to store values to recompute them for later.

+

We’ll keep an array A of length N, and A[i] will contain the length of the longest increasing subsequence ending at i. We can then use the same recurrence but look it up in the array instead:

+
1
+2
+3
+4
+5
+6
+7
+8
+9
def longest_increasing_subsequence(arr):
+    if (not arr):
+        return 0
+    cache = [1] * len(arr)
+    for (i in range(1, len(arr))):
+        for (j in range(i)):
+            if (arr[i] > arr[j]):
+                cache[i] = max(cache[i], cache[j] + 1)
+    return max(cache)
+
+

This now runs in \( O(N^2) \) time and \( O(N) \) space.

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/digit-dp/index.html b/dynamic-programming/digit-dp/index.html new file mode 100644 index 0000000..fc19659 --- /dev/null +++ b/dynamic-programming/digit-dp/index.html @@ -0,0 +1,811 @@ + + + + + + + + + + + + + + + + + + + + + Digit DP - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + +

+ + Digit DP + +

+ +
+ + +

Problems that require the calculation of how many numbers there are between two values (say, \( A \) and \( B \)) that satisfy a particular property can be solved using digit dynamic programming (Digit DP).

+
+

How to Work on Digits

+

While constructing our numbers recursively (from the left), we need a method to check if our number is still smaller than the given boundary number. To achieve this, we keep a variable called "strict" while branching, which limits our ability to select digits that are larger than the corresponding digit of the boundary number.

+

Let’s suppose the boundary number is \( A \). We start filling the number from the left (most significant digit) and set strict to true, meaning we cannot select any digit larger than the corresponding digit of \( A \). As we branch:

+
    +
  • Values less than the corresponding digit of \( A \) will now be non-strict (strict = false) because we guarantee that the number will be smaller than \( A \) after this point.
  • +
  • For values equal to the corresponding digit of \( A \), the strictness continues to be true.
  • +
+
+

Counting Problem Example

+

Problem: How many numbers \( x \) are there in the range \( A \) to \( B \), where the digit \( d \) occurs exactly \( k \) times in \( x \)?

+

Constraints: \( A, B < 10^{60}, k < 60 \).

+

Brute Force Approach:

+

The brute-force solution would involve iterating over all the numbers in the range \([A, B]\) and counting the occurrences of the digit \( d \) one by one for each number. This has a time complexity of \( O(N \log_{10}(N)) \), which is too large for such constraints, and we need a more efficient approach.

+

Recursive Approach:

+

We can recursively fill the digits of our number starting from the leftmost digit. At each step, we branch into 3 possibilities:

+
    +
  1. Pick a number that is not \( d \) and smaller than the corresponding digit of the boundary number.
  2. +
  3. Pick the digit \( d \).
  4. +
  5. Pick a number that is equal to the corresponding digit of the boundary number.
  6. +
+

The depth of recursion is equal to the number of digits in the decimal representation of the boundary number, leading to a time complexity of \( O(3^{\log_{10} N}) \). Although this is better than brute force, it is still not efficient enough.

+

Recursive Approach with Memoization:

+

We can further optimize this approach using memoization. We represent a DP state by \((\text{current index}, \text{current strictness}, \text{number of } d's)\), which denotes the number of possible configurations of the remaining digits after picking the current digit. We use a dp[\log_{10} N][2][\log_{10} N] array, where each value is computed at most once. Therefore, the worst-case time complexity is \( O((\log_{10} N)^2) \).

+

Solution Code:

+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
#include <bits/stdc++.h>
+using namespace std;
+#define ll long long
+ll A, B, d, k, dg; // dg: digit count
+vector <ll> v; // digit vector
+ll dp[25][2][25];
+void setup(ll a)
+{
+    memset(dp,0,sizeof dp);
+    v.clear();
+    ll tmp = a;
+    while(tmp)
+    {
+        v.push_back(tmp%10);
+        tmp/=10;
+    }
+    dg = (ll)v.size();
+    reverse(v.begin(), v.end());
+}
+
+ll rec(int idx, bool strict, int count)
+{
+    if(dp[idx][strict][count]) return dp[idx][strict][count];
+    if(idx == dg or count > k) return (count == k);
+    ll sum = 0;
+    if(strict)
+    {
+        // all <v[idx] if d is included -1
+        sum += rec(idx + 1, 0, count) * (v[idx] - (d < v[idx]));
+        // v[idx], if d==v[idx] send count+1
+        sum += rec(idx + 1, 1, count + (v[idx] == d) );
+        if(d < v[idx])
+        sum += rec(idx + 1, 0, count + 1); // d
+    }
+    else
+    {
+        sum += rec(idx + 1, 0, count) * (9); // other than d (10 - 1)
+        sum += rec(idx + 1, 0, count + 1); // d
+    }
+    return dp[idx][strict][count] = sum;
+}
+
+int main()
+{
+    cin >> A >> B >> d >> k;
+    setup(B);
+    ll countB = rec(0, 1, 0); //countB is answer of [0..B]
+    setup(A - 1);
+    ll countA = rec(0, 1, 0); //countA is answer of [0..A-1]
+    cout << fixed << countB - countA << endl; //difference gives us [A..B]
+}
+
+
+

References

+ + + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/dp-on-dags/index.html b/dynamic-programming/dp-on-dags/index.html new file mode 100644 index 0000000..55c3194 --- /dev/null +++ b/dynamic-programming/dp-on-dags/index.html @@ -0,0 +1,758 @@ + + + + + + + + + + + + + + + + + + + + + DP on Directed Acyclic Graphs (DAGs) - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + DP on Directed Acyclic Graphs (DAGs) + +

+ +
+ + +

As we know, the nodes of a directed acyclic graph (DAG) can be sorted topologically, and DP can be implemented efficiently using this topological order.

+

First, we can find the topological order with a topological sort in \( O(N) \) time complexity. Then, we can find the \( dp(V) \) values in topological order, where \( V \) is a node in the DAG and \( dp(V) \) is the answer for node \( V \). The answer and implementation will differ depending on the specific problem.

+
+

Converting a DP Problem into a Directed Acyclic Graph

+

Many DP problems can be converted into a DAG. Let’s explore why this is the case.

+

While solving a DP problem, when we process a state, we evaluate it by considering all possible previous states. To do this, all of the previous states must be processed before the current state. From this perspective, some states depend on other states, forming a DAG structure.

+

However, note that some DP problems cannot be converted into a DAG and may require hyper-graphs. (For more details, refer to Advanced Dynamic Programming in Semiring and Hypergraph Frameworks).

+

Example Problem:

+

There are \( N \) stones numbered \( 1, 2, ..., N \). For each \( i \) ( \( 1 \leq i \leq N \) ), the height of the \( i \)-th stone is \( h_i \). There is a frog initially on stone 1. The frog can jump to stone \( i+1 \) or stone \( i+2 \). The cost of a jump from stone \( i \) to stone \( j \) is \( | h_i − h_j | \). Find the minimum possible cost to reach stone \( N \).

+

Solution:

+

We define \( dp[i] \) as the minimum cost to reach the \( i \)-th stone. The answer will be \( dp[N] \). The recurrence relation is defined as:

+

\[ +dp[i] = \min(dp[i−1] + |h_i − h_{i−1}|, dp[i−2] + |h_i − h_{i−2}|) +\]

+

For \( N = 5 \), we can see that to calculate \( dp[5] \), we need to calculate \( dp[4] \) and \( dp[3] \). Similarly:

+
    +
  • \( dp[4] \) depends on \( dp[3] \) and \( dp[2] \),
  • +
  • \( dp[3] \) depends on \( dp[2] \) and \( dp[1] \),
  • +
  • \( dp[2] \) depends on \( dp[1] \).
  • +
+

These dependencies form a DAG, where the nodes represent the stones, and the edges represent the transitions between them based on the jumps.

+
graph LR
+    A(dp_1) --> B(dp_2);
+    A --> C(dp_3);
+    B --> D(dp_4);
+    B --> E(dp_5);
+    C --> D;
+    D --> E;
+

DP on Directed Acyclic Graph Problem

+

Given a DAG with \( N \) nodes and \( M \) weighted edges, find the longest path in the DAG.

+

Complexity:

+

The time complexity for this problem is \( O(N + M) \), where \( N \) is the number of nodes and \( M \) is the number of edges.

+

Solution Code:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
// topological sort is not written here so we will take tp as it is already sorted
+// note that tp is reverse topologically sorted
+// vector <int> tp
+// n , m and vector <pair<int,int>> adj is given.Pair denotes {node,weight}.
+// flag[] denotes whether a node is processed or not.Initially all zero.
+// dp[] is DP array.Initially all zero.
+
+for (int i = 0; i < (int)tp.size(); ++i)//processing in order
+{
+    int curNode = tp[i];
+
+    for (auto v : adj[curNode]) //iterate through all neighbours
+        if(flag[v.first]) //if a neighbour is already processed
+            dp[curNode] = max(dp[curNode] , dp[v.first] + v.second);
+
+    flag[curNode] = 1;
+}
+//answer is max(dp[1..n])
+
+
+

References

+ + + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/dp-on-rooted-trees/index.html b/dynamic-programming/dp-on-rooted-trees/index.html new file mode 100644 index 0000000..7453d45 --- /dev/null +++ b/dynamic-programming/dp-on-rooted-trees/index.html @@ -0,0 +1,744 @@ + + + + + + + + + + + + + + + + + + + + + DP on Rooted Trees - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + DP on Rooted Trees + +

+ +
+ + +

In dynamic programming (DP) on rooted trees, we define functions for the nodes of the tree, which are calculated recursively based on the children of each node. One common DP state is usually associated with a node \(i\), representing the sub-tree rooted at node \(i\).

+
+

Problem

+

Given a tree \( T \) of \( N \) (1-indexed) nodes, where each node \( i \) has \( C_i \) coins attached to it, the task is to choose a subset of nodes such that no two adjacent nodes (nodes directly connected by an edge) are chosen, and the sum of coins attached to the chosen subset is maximized.

+

Approach:

+

We define two functions, \( dp1(V) \) and \( dp2(V) \), as follows:

+
    +
  • \( dp1(V) \): The optimal solution for the sub-tree of node \( V \) when node \( V \) is included in the answer.
  • +
  • \( dp2(V) \): The optimal solution for the sub-tree of node \( V \) when node \( V \) is not included in the answer.
  • +
+

The final answer is the maximum of these two cases:

+

\[ +\text{max}(dp1(V), dp2(V)) +\]

+

Recursive Definitions:

+
    +
  • +

    \( dp1(V) = C_V + \sum_{i=1}^{n} dp2(v_i) \), where \( n \) is the number of children of node \( V \), and \( v_i \) is the \( i \)-th child of node \( V \).
    + This represents the scenario where node \( V \) is included in the chosen subset, so none of its children can be selected.

    +
  • +
  • +

    \( dp2(V) = \sum_{i=1}^{n} \text{max}(dp1(v_i), dp2(v_i)) \).
    + This represents the scenario where node \( V \) is not included, so the optimal solution for each child \( v_i \) can either include or exclude that child.

    +
  • +
+

Complexity:

+

The time complexity for this approach is \( O(N) \), where \( N \) is the number of nodes in the tree. This is because the solution involves a depth-first search (DFS) traversal of the tree, and each node is visited only once.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
//pV is parent of V
+void dfs(int V, int pV)
+{
+    //base case:
+    //when dfs reaches a leaf it finds dp1 and dp2 and does not branch again.
+
+    //for storing sums of dp1 and max(dp1, dp2) for all children of V
+    int sum1 = 0, sum2 = 0;
+
+    //traverse over all children
+    for (auto v : adj[V])
+    {
+        if (v == pV)
+            continue;
+        dfs(v, V);
+        sum1 += dp2[v];
+        sum2 += max(dp1[v], dp2[v]);
+    }
+
+    dp1[V] = C[V] + sum1;
+    dp2[V] = sum2;
+}
+//Nodes are 1-indexed, therefore our answer stored in dp1[1] and dp2[1]
+//for the answer we take max(dp1[1],dp2[1]) after calling dfs(1,0).
+
+
+

References

+ + + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/dynamic-programming/index.html b/dynamic-programming/dynamic-programming/index.html new file mode 100644 index 0000000..da1376f --- /dev/null +++ b/dynamic-programming/dynamic-programming/index.html @@ -0,0 +1,793 @@ + + + + + + + + + + + + + + + + + + + + + Dynamic Programming - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Dynamic Programming + +

+ +
+ + +

Dynamic programming (DP) is a technique used to avoid computing the same sub-solution multiple times in a recursive algorithm. A sub-solution of the problem is constructed from the previously found ones. DP solutions have a polynomial complexity, which ensures a much faster running time than other techniques like backtracking or brute-force.

+

Memoization - Top Down

+

Memoization ensures that a method doesn’t run for the same inputs more than once by keeping a record of the results for the given inputs (usually in a hash map).

+

To avoid duplicate work caused by recursion, we can use a cache that maps inputs to outputs. The approach involves:

+
    +
  • Checking the cache to see if we can avoid computing the answer for any given input.
  • +
  • Saving the results of any calculations to the cache.
  • +
+

Memoization is a common strategy for dynamic programming problems where the solution is composed of solutions to the same problem with smaller inputs, such as the Fibonacci problem.

+

Another strategy for dynamic programming is the bottom-up approach, which is often cleaner and more efficient.

+

Bottom-Up

+

The bottom-up approach avoids recursion, saving the memory cost associated with building up the call stack. It "starts from the beginning" and works towards the final solution, whereas a recursive algorithm often "starts from the end and works backwards."

+

An Example - Fibonacci

+

Let’s start with a well-known example: finding the \(n\)-th Fibonacci number. The Fibonacci sequence is defined as:

+

\[ +F_n = F_{n−1} + F_{n−2}, \quad \text{with } F_0 = 0 \text{ and } F_1 = 1 +\]

+

There are several approaches to solving this problem:

+

Recursion

+

In a recursive approach, the function calls itself to compute the previous two Fibonacci numbers until reaching the base cases.

+
1
+2
+3
+4
+5
+6
+7
def fibonacci(n):
+    if (n == 0):
+        return 0
+    if (n == 1):
+        return 1
+
+    return fibonacci(n - 1) + fibonacci(n - 2)
+
+

Dynamic Programming

+
    +
  • Top-Down - Memoization: + Recursion leads to unnecessary repeated calculations. Memoization solves this by caching the results of previously computed Fibonacci numbers, so they don't have to be recalculated.
  • +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
cache = {}
+
+def fibonacci(n):
+    if (n == 0):
+        return 0
+    if (n == 1):
+        return 1
+    if (n in cache):
+        return cache[n]
+
+    cache[n] = fibonacci(n - 1) + fibonacci(n - 2)
+
+    return cache[n]
+
+
+Recursive vs Memoization +
Visualization of Recursive Memoization
+
+
    +
  • Bottom-Up: + The bottom-up approach eliminates recursion by computing the Fibonacci numbers in order, starting from the base cases and building up to the desired value.
  • +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
cache = {}
+
+def fibonacci(n):
+    cache[0] = 0
+    cache[1] = 1
+
+    for (i in range(2, n + 1)):
+        cache[i] = cache[i - 1] + cache[i - 2]
+
+    return cache[n]
+
+

Additionally, this approach can be optimized further by using constant space and only storing the necessary partial results along the way.

+
1
+2
+3
+4
+5
+6
+7
+8
+9
def fibonacci(n):
+    fib_minus_2 = 0
+    fib_minus_1 = 1
+
+    for (i in range(2, n + 1)):
+        fib = fib_minus_1 + fib_minus_2
+        fib_minus_1, fib_minus_2 = fib, fib_minus_1
+
+    return fib
+
+

How to Apply Dynamic Programming?

+

To apply dynamic programming, follow these steps:

+
    +
  • Find the recursion in the problem: Identify how the problem can be broken down into smaller subproblems.
  • +
  • Top-down approach: Store the result of each subproblem in a table to avoid recomputation.
  • +
  • Bottom-up approach: Find the correct order to evaluate the results so that partial results are available when needed.
  • +
+

Dynamic programming generally works for problems that have an inherent left-to-right order, such as strings, trees, or integer sequences. If the naive recursive algorithm does not compute the same subproblem multiple times, dynamic programming won't be useful.

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/greedy-algorithms/index.html b/dynamic-programming/greedy-algorithms/index.html new file mode 100644 index 0000000..336c839 --- /dev/null +++ b/dynamic-programming/greedy-algorithms/index.html @@ -0,0 +1,957 @@ + + + + + + + + + + + + + + + + + + + + + Greedy Algorithms - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Greedy Algorithms + +

+ +
+ + +

A greedy algorithm is an algorithm that follows the problem solving heuristic of making the locally optimal choice at each stage with the hope of finding a global optimum. A greedy algorithm never takes back its choices, but directly constructs the final solution. For this reason, greedy algorithms are usually very efficient.

+

The difficulty in designing greedy algorithms is to find a greedy strategy that always produces an optimal solution to the problem. The locally optimal choices in a greedy algorithm should also be globally optimal. It is often difficult to argue that a greedy algorithm works.

+

Coin Problem

+

We are given a value \( V \). If we want to make change for \( V \) cents, and we have an infinite supply of each of the coins = { \( C_1, C_2, \dots, C_m \) } valued coins (sorted in descending order), what is the minimum number of coins to make the change?

+

Solution

+

Approach:

+
    +
  1. Initialize the result as empty.
  2. +
  3. Find the largest denomination that is smaller than the amount.
  4. +
  5. Add the found denomination to the result. Subtract the value of the found denomination from the amount.
  6. +
  7. If the amount becomes 0, then print the result. Otherwise, repeat steps 2 and 3 for the new value of the amount.
  8. +
+

1
+2
+3
+4
+5
+6
+7
def min_coins(coins, amount):
+    n = len(coins)
+    for i in range(n):
+        while amount >= coins[i]:
+            # while loop is needed since one coin can be used multiple times
+            amount -= coins[i]
+            print(coins[i])
+
+For example, if the coins are the euro coins (in cents) \({200, 100, 50, 20, 10, 5, 2, 1}\) and the amount is 548, the optimal solution is to select coins \(200+200+100+20+20+5+2+1\), whose sum is \(548\).

+
+Coin Change Problem +
Visualization of the Coin Change Problem
+
+

In the general case, the coin set can contain any kind of coins, and the greedy algorithm does not necessarily produce an optimal solution.

+

We can prove that a greedy algorithm does not work by showing a counterexample where the algorithm gives a wrong answer. In this problem, we can easily find a counterexample: if the coins are \({6, 5, 2}\) and the target sum is \(10\), the greedy algorithm produces the solution \(6+2+2\), while the optimal solution is \(5+5\).

+

Scheduling

+

Many scheduling problems can be solved using greedy algorithms. A classic problem is as follows:

+

We are given an array of jobs where every job has a deadline and associated profit if the job is finished before the deadline. It is also given that every job takes a single unit of time, thus the minimum possible deadline for any job is 1. How do we maximize total profit if only one job can be scheduled at a time?

+

Solution

+

A simple solution is to generate all subsets of the given set of jobs and check each subset for feasibility. Keep track of maximum profit among all feasible subsets. The time complexity of this solution is exponential. This is a standard Greedy Algorithm problem.

+

Approach:

+
    +
  1. Sort all jobs in decreasing order of profit.
  2. +
  3. Initialize the result sequence as the first job in sorted jobs.
  4. +
  5. For the remaining \(n-1\) jobs:
  6. +
  7. If the current job can fit in the current result sequence without missing the deadline, add the current job to the result.
  8. +
  9. Else ignore the current job.
  10. +
+
 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
+26
+27
# sample job : ['x', 4, 25] −> [job_id, deadline, profit]
+# jobs: array of 'job's
+def print_job_scheduling(jobs, t):
+    n = len(jobs)
+
+    # Sort all jobs according to decreasing order of profit
+    for i in range(n):
+        for j in range(n - 1 - i):
+            if jobs[j][2] < jobs[j + 1][2]:
+                jobs[j], jobs[j + 1] = jobs[j + 1], jobs[j]
+
+    # To keep track of free time slots
+    result = [False] * t
+    # To store result (Sequence of jobs)
+    job = ['-1'] * t
+
+    # Iterate through all given jobs
+    for i in range(len(jobs)):
+        # Find a free slot for this job
+        # (Note that we start from the last possible slot)
+        for j in range(min(t - 1, jobs[i][1] - 1), -1, -1):
+            # Free slot found
+            if result[j] is False:
+                result[j] = True
+                job[j] = jobs[i][0]
+                break
+    print(job)
+
+

Tasks and Deadlines

+

Let us now consider a problem where we are given \(n\) tasks with durations and deadlines, and our task is to choose an order to perform the tasks. For each task, we earn \(d - x\) points, where \(d\) is the task’s deadline and \(x\) is the moment when we finish the task. What is the largest possible total score we can obtain?

+

For example, suppose the tasks are as follows:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TaskDurationDeadline
A42
B35
C27
D45
+

An optimal schedule for the tasks is \( C, B, A, D \). In this solution, \( C \) yields 5 points, \( B \) yields 0 points, \( A \) yields -7 points, and \( D \) yields -8 points, so the total score is -10.

+

Interestingly, the optimal solution to the problem does not depend on the deadlines, but a correct greedy strategy is to simply perform the tasks sorted by their durations in increasing order.

+

Solution

+
    +
  1. Sort all tasks according to increasing order of duration.
  2. +
  3. Calculate the total points by iterating through all tasks, summing up the difference between the deadlines and the time at which the task is finished.
  4. +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
def order_tasks(tasks):
+    n = len(tasks)
+
+    # Sort all task according to increasing order of duration
+    for (i in range(n)):
+        for (j in range(n - 1 - i)):
+            if (tasks[j][1] > tasks[j + 1][1]):
+                tasks[j], tasks[j + 1] = tasks[j + 1], tasks[j]
+
+    point = 0
+    current_time = 0
+    # Iterate through all given tasks and calculate point
+    for (i in range(len(tasks))):
+        current_time = current_time + tasks[i][1]
+        point = point + (tasks[i][2] - current_time)
+
+    print(point)
+
+

Minimizing Sums

+

We are given \(n\) numbers and our task is to find a value \(x\) that minimizes the sum:

+

\[ +|a_1 − x|^c + |a_2 − x|^c + ... + |a_n − x|^c +\]

+

We focus on the cases \(c = 1\) and \(c = 2\).

+

Case \(c = 1\)

+

In this case, we should minimize the sum:

+

\[ +|a_1 − x| + |a_2 − x| + ... + |a_n − x| +\]

+

For example, if the numbers are \([1, 2, 9, 2, 6]\), the best solution is to select \(x = 2\), which produces the sum:

+

\[ +|1 − 2| + |2 − 2| + |9 − 2| + |2 − 2| + |6 − 2| = 12 +\]

+

In the general case, the best choice for \(x\) is the median of the numbers. For instance, the list \([1, 2, 9, 2, 6]\) becomes \([1, 2, 2, 6, 9]\) after sorting, so the median is 2. The median is an optimal choice because if \(x\) is smaller than the median, the sum decreases by increasing \(x\), and if \(x\) is larger, the sum decreases by lowering \(x\). Hence, the optimal solution is \(x = \text{median}\).

+

Case \(c = 2\)

+

In this case, we minimize the sum:

+

\[ +(a_1 − x)^2 + (a_2 − x)^2 + ... + (a_n − x)^2 +\]

+

For example, if the numbers are \([1, 2, 9, 2, 6]\), the best solution is to select \(x = 4\), which produces the sum:

+

\[ +(1 − 4)^2 + (2 − 4)^2 + (9 − 4)^2 + (2 − 4)^2 + (6 − 4)^2 = 46 +\]

+

In the general case, the best choice for \(x\) is the average of the numbers. For the given example, the average is:

+

\[ +\frac{(1 + 2 + 9 + 2 + 6)}{5} = 4 +\]

+

This result can be derived by expressing the sum as:

+

\[ +n x^2 − 2x(a_1 + a_2 + ... + a_n) + (a_1^2 + a_2^2 + ... + a_n^2) +\]

+

The last part does not depend on \(x\), so we can ignore it. The remaining terms form a function with a parabola opening upwards, and the minimum value occurs at \(x = \frac{s}{n}\), where \(s\) is the sum of the numbers, i.e., the average of the numbers.

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/dynamic-programming/img/1st_power_matrix.png b/dynamic-programming/img/1st_power_matrix.png similarity index 100% rename from docs/dynamic-programming/img/1st_power_matrix.png rename to dynamic-programming/img/1st_power_matrix.png diff --git a/docs/dynamic-programming/img/3rd_power_matrix.png b/dynamic-programming/img/3rd_power_matrix.png similarity index 100% rename from docs/dynamic-programming/img/3rd_power_matrix.png rename to dynamic-programming/img/3rd_power_matrix.png diff --git a/docs/dynamic-programming/img/coin_change.png b/dynamic-programming/img/coin_change.png similarity index 100% rename from docs/dynamic-programming/img/coin_change.png rename to dynamic-programming/img/coin_change.png diff --git a/docs/dynamic-programming/img/left_childright_sibling.png b/dynamic-programming/img/left_childright_sibling.png similarity index 100% rename from docs/dynamic-programming/img/left_childright_sibling.png rename to dynamic-programming/img/left_childright_sibling.png diff --git a/docs/dynamic-programming/img/recursive_memoization.png b/dynamic-programming/img/recursive_memoization.png similarity index 100% rename from docs/dynamic-programming/img/recursive_memoization.png rename to dynamic-programming/img/recursive_memoization.png diff --git a/dynamic-programming/index.html b/dynamic-programming/index.html new file mode 100644 index 0000000..cdc566e --- /dev/null +++ b/dynamic-programming/index.html @@ -0,0 +1,885 @@ + + + + + + + + + + + + + + + + + + + + + + + Dynamic Programming - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + +

+ + Dynamic Programming + +

+ +
+ + +

Editor: Halil Çetiner

+

Reviewers: Onur Yıldız

+

Introduction

+

Next section is about the Greedy Algorithms and Dynamic Programming. It will be quite a generous introduction to the concepts and will be followed by some common problems.

+

Greedy Algorithms

+

Dynamic Programming

+

Common DP Problems

+

Bitmask DP

+

DP on Rooted Trees

+

DP on Directed Acyclic Graphs

+

Digit DP

+

Walk Counting using Matrix Exponentiation

+

Tree Child-Sibling Notation

+

References

+
    +
  1. "Competitive Programmer’s Handbook" by Antti Laaksonen - Draft July 3, 2018
  2. +
  3. Wikipedia - Dynamic Programming
  4. +
  5. Topcoder - Competitive Programming Community / Dynamic Programming from Novice to Advanced
  6. +
  7. Hacker Earth - Dynamic Programming
  8. +
  9. Geeks for Geeks - Dynamic Programming
  10. +
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/tree-child-sibling-notation/index.html b/dynamic-programming/tree-child-sibling-notation/index.html new file mode 100644 index 0000000..4406ab4 --- /dev/null +++ b/dynamic-programming/tree-child-sibling-notation/index.html @@ -0,0 +1,700 @@ + + + + + + + + + + + + + + + + + + + + + Tree Child-Sibling Notation - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + +

+ + Tree Child-Sibling Notation + +

+ +
+ + +

In this method, we change the structure of the tree. In a standard tree, each parent node is connected to all of its children. However, in the child-sibling notation, a node stores a pointer to only one of its children. Additionally, the node also stores a pointer to its immediate right sibling.

+

In this notation, every node has at most 2 children: +- Left child (first child), +- Right sibling (first sibling).

+

This structure is called the LCRS (Left Child-Right Sibling) notation. It effectively represents a binary tree, as every node has only two pointers (left and right).

+
+Child-Sibling Notation +
a tree notated with child-sibling notation
+
+

Why You Would Use the LCRS Notation

+

The primary reason for using LCRS notation is to save memory. In the LCRS structure, less memory is used compared to the standard tree notation.

+

When You Might Use the LCRS Notation:

+
    +
  • Memory is extremely scarce.
  • +
  • Random access to a node’s children is not required.
  • +
+

Possible Cases for Using LCRS:

+
    +
  1. +

    When storing a large multi-way tree in main memory:
    + For example, the phylogenetic tree.

    +
  2. +
  3. +

    In specialized data structures where the tree is used in specific ways:
    + For example, in the heap data structure, the main operations are:

    +
  4. +
  5. +

    Removing the root of the tree and processing each of its children,

    +
  6. +
  7. Joining two trees together by making one tree a child of the other.
  8. +
+

These operations can be done efficiently using the LCRS structure, making it convenient for working with heap data structures.

+
+

References

+ + + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamic-programming/walk-counting-with-matrix/index.html b/dynamic-programming/walk-counting-with-matrix/index.html new file mode 100644 index 0000000..20a9c37 --- /dev/null +++ b/dynamic-programming/walk-counting-with-matrix/index.html @@ -0,0 +1,700 @@ + + + + + + + + + + + + + + + + + + + + + Walk Counting using Matrix Exponentiation - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Walk Counting using Matrix Exponentiation + +

+ +
+ + +

Matrix exponentiation can be used to count the number of walks of a given length on a graph.

+

Let \( l \) be the desired walk length, and let \( A \) and \( B \) be nodes in a graph \( G \). If \( D \) is the adjacency matrix of \( G \), then \( D^l[A][B] \) represents the number of walks from node \( A \) to node \( B \) with length \( l \), where \( D^k \) denotes the \( k \)-th power of the matrix \( D \).

+
+

Explanation:

+
    +
  • Adjacency Matrix \( D \):
    + In the adjacency matrix of a graph, each entry \( D[i][j] \) denotes whether there is a direct edge between node \( i \) and node \( j \). Specifically:
  • +
  • \( D[i][j] = 1 \) if there is an edge from \( i \) to \( j \),
  • +
  • +

    \( D[i][j] = 0 \) otherwise.

    +
  • +
  • +

    Matrix Exponentiation:
    + To find the number of walks of length \( l \) between nodes \( A \) and \( B \), we need to compute \( D^l \), which is the \( l \)-th power of the adjacency matrix \( D \). The entry \( D^l[A][B] \) will then give the number of walks of length \( l \) from node \( A \) to node \( B \).

    +
  • +
+
graph LR
+    A(2) --> B(1);
+    B --> C(3);
+    C --> A;
+    C --> D(4);
+    D --> C;
+ + + + + + + + + + + + + +
D, adjacency matrix of GD^3, 3rd power of the matrix D
D, adjacency matrix of GD^3, 3rd power of the matrix D
+

From the matrix \( D^3 \), we can see that there are 4 total walks of length 3.

+

Let \( S \) be the set of walks, and let \( w \) be a walk where \( w = \{n_1, n_2, ..., n_k\} \) and \( n_i \) is the \( i \)-th node of the walk. Then:

+

[ +S = {{1, 3, 4, 3}, {3, 4, 3, 2}, {3, 4, 3, 4}, {4, 3, 4, 3}} +] +and \( |S| = 4 \).

+

Using fast exponentiation on the adjacency matrix, we can efficiently find the number of walks of length \( k \) in \( O(N^3 \log k) \) time, where \( N \) is the number of nodes in the graph.

+

Time Complexity Breakdown:

+
    +
  • Matrix Multiplication: The \( O(N^3) \) time complexity comes from multiplying two \( N \times N \) matrices.
  • +
  • Fast Exponentiation: Fast exponentiation reduces the number of multiplications to \( \log k \), resulting in the overall time complexity of \( O(N^3 \log k) \).
  • +
+

This method allows for efficiently calculating the number of walks with any length \( k \) in large graphs.

+
+

References

+ + + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/binary-search-tree/index.html b/graph/binary-search-tree/index.html new file mode 100644 index 0000000..9290ccd --- /dev/null +++ b/graph/binary-search-tree/index.html @@ -0,0 +1,897 @@ + + + + + + + + + + + + + + + + + + + + + Binary Search Tree - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Binary Search Tree + +

+ +
+ + +

A Binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child.

+

For a binary tree to be a binary search tree, the values of all the nodes in the left sub-tree of the root node should be smaller than the root node's value. Also the values of all the nodes in the right sub-tree of the root node should be larger than the root node's value.

+
+a simple binary search tree +
a simple binary search tree
+
+

Insertion Algorithm

+
    +
  1. Compare values of the root node and the element to be inserted.
  2. +
  3. If the value of the root node is larger, and if a left child exists, then repeat step 1 with root = current root's left child. Else, insert element as left child of current root.
  4. +
  5. If the value of the root node is lesser, and if a right child exists, then repeat step 1 with root = current root's right child. Else, insert element as right child of current root.
  6. +
+

Deletion Algorithm

+
    +
  • Deleting a node with no children: simply remove the node from the tree.
  • +
  • Deleting a node with one child: remove the node and replace it with its child.
  • +
  • Node to be deleted has two children: Find inorder successor of the node. Copy contents of the inorder successor to the node and delete the inorder successor.
  • +
  • Note that: inorder successor can be obtained by finding the minimum value in right child of the node.
  • +
+

Sample Code

+
  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
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
// C program to demonstrate delete operation in binary search tree 
+#include<stdio.h>
+#include<stdlib.h>
+
+struct node
+{
+    int key;
+    struct node *left, *right;
+};
+
+// A utility function to create a new BST node
+struct node *newNode(int item)
+{
+    struct node *temp = (struct node *)malloc(sizeof(struct node));
+    temp->key = item;
+    temp->left = temp->right = NULL;
+    return temp;
+}
+
+// A utility function to do inorder traversal of BST
+void inorder(struct node *root)
+{
+    if (root != NULL)
+    {
+        inorder(root->left);
+        printf("%d ", root->key);
+        inorder(root->right);
+    }
+}
+
+/* A utility function to insert a new node with given key in BST */
+struct node* insert(struct node* node, int key)
+{
+    /* If the tree is empty, return a new node */
+    if (node == NULL) return newNode(key);
+
+    /* Otherwise, recur down the tree */
+    if (key < node->key)
+        node->left = insert(node->left, key);
+    else
+        node->right = insert(node->right, key);
+
+    /* return the (unchanged) node pointer */
+    return node;
+}
+
+/* Given a non-empty binary search tree, return the node with minimum
+   key value found in that tree. Note that the entire tree does not
+   need to be searched. */
+struct node * minValueNode(struct node* node)
+{
+    struct node* current = node;
+
+    /* loop down to find the leftmost leaf */
+    while (current->left != NULL)
+        current = current->left;
+
+    return current;
+}
+
+/* Given a binary search tree and a key, this function deletes the key
+   and returns the new root */
+struct node* deleteNode(struct node* root, int key)
+{
+    // base case
+    if (root == NULL) return root;
+
+    // If the key to be deleted is smaller than the root's key,
+    // then it lies in left subtree
+    if (key < root->key)
+        root->left = deleteNode(root->left, key);
+
+    // If the key to be deleted is greater than the root's key,
+    // then it lies in right subtree
+    else if (key > root->key)
+        root->right = deleteNode(root->right, key);
+
+    // if key is same as root's key, then This is the node
+    // to be deleted
+    else
+    {
+        // node with only one child or no child
+        if (root->left == NULL)
+        {
+            struct node *temp = root->right;
+            free(root);
+            return temp;
+        }
+        else if (root->right == NULL)
+        {
+            struct node *temp = root->left;
+            free(root);
+            return temp;
+        }
+
+        // node with two children: Get the inorder successor (smallest
+        // in the right subtree)
+        struct node* temp = minValueNode(root->right);
+
+        // Copy the inorder successor's content to this node
+        root->key = temp->key;
+
+        // Delete the inorder successor
+        root->right = deleteNode(root->right, temp->key);
+    }
+    return root;
+}
+
+

Time Complexity

+

The worst case time complexity of search, insert, and deletion operations is \(\mathcal{O}(h)\) where h is the height of Binary Search Tree. In the worst case, we may have to travel from root to the deepest leaf node. The height of a skewed tree may become \(N\) and the time complexity of search and insert operation may become \(\mathcal{O}(N)\). So the time complexity of establishing \(N\) node unbalanced tree may become \(\mathcal{O}(N^2)\) (for example the nodes are being inserted in a sorted way). But, with random input the expected time complexity is \(\mathcal{O}(NlogN)\).

+

However, you can implement other data structures to establish Self-balancing binary search tree (which will be taught later), popular data structures that implementing this type of tree include:

+
    +
  • 2-3 tree
  • +
  • AA tree
  • +
  • AVL tree
  • +
  • B-tree
  • +
  • Red-black tree
  • +
  • Scapegoat tree
  • +
  • Splay tree
  • +
  • Treap
  • +
  • Weight-balanced tree
  • +
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/bipartite-checking/index.html b/graph/bipartite-checking/index.html new file mode 100644 index 0000000..39b4652 --- /dev/null +++ b/graph/bipartite-checking/index.html @@ -0,0 +1,686 @@ + + + + + + + + + + + + + + + + + + + + + Bipartite Checking - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Bipartite Checking + +

+ +
+ + +

The question is in the title. Is the given graph bipartite? We can use BFS or DFS on graph. Lets first focus on BFS related algorithm. This procedure is very similar to BFS, we have an extra color array and we assign a color to each vertex when we are traversing the graph. Algorithm proof depends on fact that BFS explores the graph level by level. If the graph contains an odd cycle it means that there must be a edge between two vertices that are in same depth (layer, proof can be found on [1 - Algorithm Design, Kleinberg, Tardos]). Let's say the colors are red and black and we traverse the graph with BFS and assign red to odd layers and black to even layers. Then we check the edges to see if there exists an edge that its vertices are same color. If there is a such edge, the graph is not bipartite, else the graph is bipartite.

+
+If two nodes x and y in the same layer are joined by an edge, then the cycle through x, y, and their lowest common ancestor z has odd length, demonstrating that the graph cannot be bipartite. +
If two nodes x and y in the same layer are joined by an edge, then the cycle through x, y, and their lowest common ancestor z has odd length, demonstrating that the graph cannot be bipartite.
+
+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
typedef vector<int> adjList;
+typedef vector<adjList> graph;
+typedef pair<int,int> ii;
+enum COLOR {RED, GREEN};
+bool bipartite_check(graph &g){
+    int root = 0; // Pick 0 indexed node as root.
+    vector<bool> visited(g.size(),false);
+    vector<int> Color(g.size(),0); 
+    queue<ii> Q( { {root,0}} ); // insert root to queue, it is  first layer_0
+    visited[root] = true;
+    Color[root] = RED;
+    while ( !Q.empty() )
+    {
+        /*top.first is node, top.second its depth i.e layer */
+        auto top = Q.front();
+        Q.pop();
+        for (int u : g[top.first]){
+            if ( !visited[u] ){
+                visited[u] = true;
+                //Mark even layers to red, odd layers to green
+                Color[u] = (top.second+1) % 2 == 0 ?  RED : GREEN; 
+                Q.push({u, top.second+1 });
+            }
+        }
+    }
+    for(int i=0; i < g.size(); ++i){
+        for( auto v: g[i]){
+            if ( Color[i] == Color[v] ) return false;
+        }
+    }
+    return true;
+}
+int main(){
+    graph g(3);
+    g[0].push_back(1);
+    g[1].push_back(2);
+    g[2].push_back(3);
+    cout << (bipartite_check(g) == true ? "YES" : "NO") << endl;
+    return 0;
+}
+
+

The complexity of algorithm is is $O(V + E) + O(E) $, BFS and loop over edges. But we can say it \(O(V+E)\) since it is Big-O notation.

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/breadth-first-search/index.html b/graph/breadth-first-search/index.html new file mode 100644 index 0000000..9371952 --- /dev/null +++ b/graph/breadth-first-search/index.html @@ -0,0 +1,737 @@ + + + + + + + + + + + + + + + + + + + + + Breadth First Search - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Breadth First Search + +

+ +
+ + +

Breadth First Search (BFS) is an algorithm for traversing or searching tree. (For example, you can find the shortest path from one node to another in an unweighted graph.)

+
+Breadth First Search Traversal +
An example breadth first search traversal
+
+

Method

+

BFS is a traversing algorithm where you should start traversing from a selected node (source or starting node) and traverse the graph layerwise thus exploring the neighbour nodes (nodes which are directly connected to source node). You must then move towards the next-level neighbour nodes. [1]

+

• As the name BFS suggests, you are required to traverse the graph breadthwise as follows: +• First move horizontally and visit all the nodes of the current layer +• Add to the queue neighbour nodes of current layer. +• Move to the next layer, which are in the queue

+

Example question: Given a unweighted graph, a source and a destination, we need to find shortest path from source to destination in the graph in most optimal way?

+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
#include <bits/stdc++.h>
+using namespace std;
+
+cont int MaxN=100005; // Max number of nodes 5
+
+vector <int> adj[MaxN];
+bool mark[MaxN];
+
+void bfs(int starting_point,int ending_point) {
+    memset(mark,0,sizeof(mark)); //clear the cache
+    queue <pair <int,int> > q; // the value of node
+    // , and length between this node and the starting node
+
+    q.push_back(make_pair(starting_point,0));
+    mark[starting_point]=1;
+
+    while(q.empty()==false) {
+        pair <int,int> tmp = q.front(); // get the next node
+        q.pop(); // delete from q
+
+        if(ending_point==tmp.first) {
+            printf("The length of path between %d - %d : %d\n",
+            starting_point,ending_point,tmp.second);
+            return;
+        }
+
+        for (auto j : adj[tmp.first]) {
+            if(mark[j]) continue ; // if it reached before
+            mark[j]=1;
+            q.push_back(make_pair(j,tmp.second+1)); // add next node to queue
+        }
+    }
+}
+
+int main() {
+    cin » n
+
+    for (int i=0 ; i < m; i++) {
+        cin » a » b;
+        adj[a].push_back(b);
+    }
+
+    cin » start_point » end_point;
+    bfs(start_point);
+    return 0;
+}
+
+

Complexity

+

The time complexity of BFS is \(O(V + E)\), where \(V\) is the number of nodes and \(E\) is the number of edges.

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/bridges-and-articulation-points/index.html b/graph/bridges-and-articulation-points/index.html new file mode 100644 index 0000000..0ca9076 --- /dev/null +++ b/graph/bridges-and-articulation-points/index.html @@ -0,0 +1,828 @@ + + + + + + + + + + + + + + + + + + + + + Bridges and Articulation Points - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Bridges and Articulation Points + +

+ +
+ + +

DFS Order

+

DFS order is traversing all the nodes of a given graph by fixing the root node in the same way as in the DFS algorithm, but without revisiting a discovered node. An important observation here is that the edges and nodes we use will form a tree structure. This is because, for every node (except the root), we only arrive from another node, and for the root node, we do not arrive from any other node, thus forming a tree structure.

+
1
+2
+3
+4
+5
+6
void dfs(int node){
+    used[node] = true;
+    for(auto it : g[node])
+        if(!used[it])
+            dfs(it);
+}
+
+

Types of Edges

+

When traversing a graph using DFS order, several types of edges can be encountered. These edges will be very helpful in understanding some graph algorithms.

+

Types of Edges: +- Tree edge: These are the main edges used while traversing the graph. +- Forward edge: These edges lead to a node that has been visited before and is located in our own subtree. +- Back edge: These edges lead to nodes that have been visited before but where the DFS process is not yet complete. +- Cross edge: These edges lead to nodes that have been visited before and where the DFS process is already complete.

+

An important observation about these edges is that in an undirected graph, it is impossible to have a cross edge. This is because it is not possible for an edge emerging from a node where the DFS process is complete to remain unvisited.

+
+Green-colored edges are tree edges. Edge (1,8) is a forward edge. Edge (6,4) is a back edge. Edge (5,4) is a cross edge. +
Green-colored edges are tree edges. Edge (1,8) is a forward edge. Edge (6,4) is a back edge. Edge (5,4) is a cross edge.
+
+

Bridge

+

In an undirected and connected graph, if removing an edge causes the graph to become disconnected, this edge is called a bridge.

+

Finding Bridges

+

Although there are several algorithms to find bridges (such as Chain Decomposition), we will focus on Tarjan's Algorithm, which is among the easiest to implement and the fastest.

+

When traversing a graph using DFS, if there is a back edge coming out of the subtree of the lower endpoint of an edge, then that edge is not a bridge. This is because the back edge prevents the separation of the subtree and its ancestors when the edge is removed.

+

This algorithm is based exactly on this principle, keeping track of the minimum depth reached by the back edges within the subtree of each node.

+

If the minimum depth reached by the back edges in the subtree of the lower endpoint of an edge is greater than or equal to the depth of the upper endpoint, then this edge is a bridge. This is because no back edge in the subtree of the edge's lower endpoint reaches a node above the current edge. Therefore, if we remove this edge, the subtree and its ancestors become disconnected.

+

Using Tarjan's Algorithm, we can find all bridges in a graph with a time complexity of \(\mathcal{O}(V + E)\), where \(V\) represents the number of vertices and \(E\) represents the number of edges in the graph.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
int dfs(int node, int parent, int depth) {
+    int minDepth = depth;
+    dep[node] = depth;  // dep dizisi her dugumun derinligini tutmaktadir.
+    used[node] = true;
+    for (auto it : g[node]) {
+        if (it == parent)
+            continue;
+        if (used[it]) {
+            minDepth = min(minDepth, dep[it]);
+            // Eger komsu dugum daha once kullanilmis ise
+            // Bu edge back edge veya forward edgedir.
+            continue;
+        }
+        int val = dfs(it, node, depth + 1);
+        // val degeri alt agacindan yukari cikan minimum derinliktir.
+        if (val >= depth + 1)
+            bridges.push_back({node, it});
+        minDepth = min(minDepth, val);
+    }
+    return minDepth;
+}
+
+

Articulation Point

+

In an undirected graph, if removing a node increases the number of connected components, that node is called an articulation point or cut point.

+
+For example, if we remove node 0, the remaining nodes are split into two groups: 5 and 1, 2, 3, 4. Similarly, if we remove node 1, the nodes are split into 5, 0 and 2, 3, 4. Therefore, nodes 0 and 1 are **articulation points**. +
For example, if we remove node 0, the remaining nodes are split into two groups: 5 and 1, 2, 3, 4. Similarly, if we remove node 1, the nodes are split into 5, 0 and 2, 3, 4. Therefore, nodes 0 and 1 are **articulation points**.
+
+

Finding Articulation Points

+

Tarjan's Algorithm for finding articulation points in an undirected graph:

+
    +
  • +

    Traverse the graph using DFS order.

    +
  • +
  • +

    For each node, calculate the depth of the minimum depth node that can be reached from the current node and its subtree through back edges. This value is called the low value of the node.

    +
  • +
  • +

    If the low value of any child of a non-root node is greater than or equal to the depth of the current node, then the current node is an articulation point. This is because no back edge in the subtree of this node can reach a node above the current node. Therefore, if this node is removed, its subtree will become disconnected from its ancestors.

    +
  • +
  • +

    If the current node is the root (the starting node of the DFS order) and there are multiple branches during the DFS traversal, then the root itself is an articulation point. This is because the root has multiple connected subgraphs.

    +
  • +
+

Using Tarjan's Algorithm, we can find all articulation points in a graph with a time complexity of \(\mathcal{O}(V + E)\), where \(V\) is the number of vertices and \(E\) is the number of edges in the graph.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
int dfs(int node, int parent, int depth) {
+    int minDepth = depth, children = 0;
+    dep[node] = depth;  // dep array holds depth of each node.
+    used[node] = true;
+    for (auto it : g[node]) {
+        if (it == parent)
+            continue;
+        if (used[it]) {
+            minDepth = min(minDepth, dep[it]);
+            continue;
+        }
+        int val = dfs(it, node, depth + 1);
+        if (val >= depth and parent != -1)
+            isCutPoint[node] = true;
+        minDepth = min(minDepth, val);
+        children++;
+    }
+    // This if represents the root condition that we mentioned above.
+    if (parent == -1 and children >= 2)
+        isCutPoint[node] = true;
+    return minDepth;
+}
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/cycle-finding/index.html b/graph/cycle-finding/index.html new file mode 100644 index 0000000..c0ad9c1 --- /dev/null +++ b/graph/cycle-finding/index.html @@ -0,0 +1,640 @@ + + + + + + + + + + + + + + + + + + + + + Cycle Finding - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Cycle Finding + +

+ +
+ + +

Cycle: A sequence of nodes that returns to the starting node while visiting each node at most once and contains at least two nodes.

+

We can use dfs order in order to find the graph has a cycle or not.

+

If we find a back edge while traversing the graph then we can say that graph has a cycle. Because back edge connects the nodes at the top and bottom ends and causes a cycle.

+

The algorithm that we are going to use to find the cycle in the directed graph:

+
    +
  • Traverse the graph with dfs order.
  • +
  • When you come to a node, color it gray and start visiting its neighbors.
  • +
  • If one of the current node's neighbors is gray, then there is a cycle in the graph. Because a gray node is definitely an ancestor of the current node, and an edge to one of its ancestors is definitely a back edge.
  • +
  • Once you're done visiting the neighbors, color the node black.
  • +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
bool dfs(int node){
+    // The color array holds the color of each node.
+    // 0 represents white, 1 represents gray, and 2 represents black.
+    color[node] = 1;
+    for(int i = 0; i < g[node].size(); i++){
+        int child = g[node][i];
+        if(color[child] == 1)
+            return true;
+        if(!color[child])
+            if(dfs(child))
+                return true;
+    }
+    color[node] = 2;
+    return false;
+}
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/definitions/index.html b/graph/definitions/index.html new file mode 100644 index 0000000..ab7fd7c --- /dev/null +++ b/graph/definitions/index.html @@ -0,0 +1,715 @@ + + + + + + + + + + + + + + + + + + + + + Graph Definitions - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + +

+ + Graph Definitions + +

+ +
+ + +

Definitions of Common Terms

+
    +
  • Node - An individual data element of a graph is called Node. Node is also known as vertex.
  • +
  • Edge - An edge is a connecting link between two nodes. It is represented as e = {a,b} Edge is also called Arc.
  • +
  • Adjacent - Two vertices are adjacent if they are connected by an edge.
  • +
  • Degree - a degree of a node is the number of edges incident to the node.
  • +
  • Undirected Graphs - Undirected graphs have edges that do not have a direction. The edges indicate a two-way relationship, in that each edge can be traversed in both directions.
  • +
  • Directed Graphs - Directed graphs have edges with direction. The edges indicate a one-way relationship, in that each edge can only be traversed in a single direction.
  • +
  • Weighted Edges - If each edge of graphs has an association with a real number, this is called its weight.
  • +
  • Self-Loop - It is an edge having the same node for both destination and source point.
  • +
  • Multi-Edge - Some Adjacent nodes may have more than one edge between each other.
  • +
+

Walks, Trails, Paths, Cycles and Circuits

+
    +
  • Walk - A sequence of nodes and edges in a graph.
  • +
  • Trail - A walk without visiting the same edge.
  • +
  • Circuit - A trail that has the same node at the start and end.
  • +
  • Path - A walk without visiting same node.
  • +
  • Cycle - A circuit without visiting same node.
  • +
+

Special Graphs

+
    +
  • Complete Graph - A graph having at least one edge between every two nodes.
  • +
  • Connected Graph - A graph with paths between every pair of nodes.
  • +
  • Tree - an undirected connected graph that has any two nodes that are connected by exactly one path. There are some other definitions that you can notice it is tree:
      +
    • an undirected graph is connected and has no cycles. an undirected graph is acyclic, and a simple cycle is formed if any edge is added to the graph.
    • +
    • an undirected graph is connected, it will become disconnected if any edge is removed.
    • +
    • an undirected graph is connected, and has (number of nodes - 1) edges.
    • +
    +
  • +
+

Bipartite Graphs

+

A bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets U and V such that every edge connects a vertex in U to one in V. Vertex sets U and V are usually called the parts of the graph. [1]. The figure is shown in below. It is similar to graph coloring with two colors. Coloring graph with two colors is that every vertex have a corresponding color, and for any edge, it's vertices should be different color. In other words, if we can color neighbours two different colors, we can say that graph is bipartite.

+
+Example bipartite graph, all edges satisfy the coloring constraint +
Example bipartite graph, all edges satisfy the coloring constraint
+
+

We have some observations here. +- A graph 2- colorable if and only if it is bipartite. +- A graph does not contain odd-length cycle if and only if it is bipartite. +- Every tree is a bipartite graph since trees do not contain any cycles.

+

Directed Acyclic Graphs

+

A directed acyclic graph(DAG) is a finite directed graph with no directed cycles. Equivalently, a DAG is a directed graph that has a topological ordering (we cover it in this bundle), a sequence of the vertices such that every edge is directed from earlier to later in the sequence [2]. DAGs can be used to encode precedence relations or dependencies in a natural way [3 - Algorithm Design, Kleinberg, Tardos]. There are several applications using topological ordering directly such as finding critical path or automatic differentiation on computational graphs (this is extremely useful for deep learning frameworks [4]).

+
+Example Directed Acyclic Graphs +
Example Directed Acyclic Graphs
+
+
+Example computational graph also a DAG, partial derivatives are written to edges respect to topological order +
Example computational graph also a DAG, partial derivatives are written to edges respect to topological order
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/depth-first-search/index.html b/graph/depth-first-search/index.html new file mode 100644 index 0000000..a5d75d0 --- /dev/null +++ b/graph/depth-first-search/index.html @@ -0,0 +1,761 @@ + + + + + + + + + + + + + + + + + + + + + Depth First Search - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Depth First Search + +

+ +
+ + +

Depth First Search (DFS) is an algorithm for traversing or searching tree. (For example, you can check if graph is connected or not via DFS) [2]

+
+Depth First Search +
Example of DFS traversal
+
+

Method

+

The DFS algorithm is a recursive algorithm that uses the idea of backtracking. It involves exhaustive searches of all the nodes by going ahead, if possible, else by backtracking.

+

Here, the word backtrack means that when you are moving forward and there are no more nodes along the current path, you move backwards on the same path to find nodes to traverse. All the nodes will be visited on the current path till all the unvisited nodes have been traversed after which the next path will be selected. [3]

+
1
+2
+3
+4
+5
+6
+7
+8
+9
vector<vector<int» adj; // graph represented as an adjacency list
+int n; // number of vertices
+vector<bool> visited;
+void dfs(int v) {
+    visited[v] = true;
+    for (int u : adj[v]) {
+        if (!visited[u]) dfs(u);
+    }
+}
+
+

This recursive nature of DFS can be implemented using stacks. The basic idea is as follows: Pick a starting node and push all its adjacent nodes into a stack. Pop a node from stack to select the next node to visit and push all its adjacent nodes into a stack. Repeat this process until the stack is empty. However, ensure that the nodes that are visited are marked. This will prevent you from visiting the same node more than once. If you do not mark the nodes that are visited and you visit the same node more than once, you may end up in an infinite loop. [3]

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
DFS-iterative(G, s): //Where G is graph and s is source vertex let S be stack
+S.push(s) //Inserting s in stack
+mark s as visited.
+while ( S is not empty):
+    //Pop a vertex from stack to visit next v = S.top( )
+    S.pop( )
+    //Push all the neighbours of v in stack that are not visited
+    for all neighbours w of v in Graph G:
+        if w is not visited :
+            S.push(w)
+            mark w as visited
+
+

Example Question: Given an undirected graph, find out whether the graph is strongly connected or not? An undirected graph is strongly connected if there is a path between any two pair of vertices.

+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
#include <bits/stdc++.h>
+using namespace std;
+
+cont int MaxN=100005; // Max number of nodes
+
+vector <int> adj[MaxN];
+bool mark[MaxN];
+
+void dfs(int k) {
+    mark[k]=1; // visited
+    for(auto j : adj[k]) // iterate over adjacent nodes
+        if(mark[j]==false) // check if it is visited or not
+            dfs(j); // do these operation for that node
+}
+
+int main() {
+    cin » n » m; // number of nodes , number of edges
+    for (int i=0 ; i < m; i++){
+        cin » a » b;
+        adj[a].push_back(b);
+        adj[b].push_back(a);
+    }
+
+    dfs(1);
+
+    bool connected=1;
+    for(int i=1 ; i <= n ;i++)
+        if(mark[i]==0) {
+            connected=0;
+            break;
+        }
+
+    if(connected)
+        cout « "Graph is connected" « endl;
+    else
+        cout « "Graph is not connected" « endl;
+
+    return 0;
+}
+
+

Complexity

+

The time complexity of DFS is \(O(V+E)\) when implemented using an adjacency list ( with Adjacency Matrices it is \(O(V^2)\)), where \(V\) is the number of nodes and \(E\) is the number of edges. [4]

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/heap/index.html b/graph/heap/index.html new file mode 100644 index 0000000..6f19935 --- /dev/null +++ b/graph/heap/index.html @@ -0,0 +1,847 @@ + + + + + + + + + + + + + + + + + + + + + Heap - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Heap + +

+ +
+ + +
+a simple binary search tree +
an example max-heap with 9 nodes
+
+

The heap is a complete binary tree with N nodes, the value of all the nodes in the left and right sub-tree of the root node should be smaller than the root node's value.

+

In a heap, the highest (or lowest) priority element is always stored at the root. A heap is not a sorted structure and can be regarded as partially ordered. As visible from the heap-diagram, there is no particular relationship among nodes on any given level, even among the siblings. Because a heap is a complete binary tree, it has a smallest possible height. A heap with \(N\) nodes has \(logN\) height. A heap is a useful data structure when you need to remove the object with the highest (or lowest) priority.

+

Implementation

+

Heaps are usually implemented in an array (fixed size or dynamic array), and do not require pointers between elements. After an element is inserted into or deleted from a heap, the heap property may be violated and the heap must be balanced by internal operations.

+

The first (or last) element will contain the root. The next two elements of the array contain its children. The next four contain the four children of the two child nodes, etc. Thus the children of the node at position n would be at positions \(2*n\) and \(2*n + 1\) in a one-based array. This allows moving up or down the tree by doing simple index computations. Balancing a heap is done by sift-up or sift-down operations (swapping elements which are out of order). So we can build a heap from an array without requiring extra memory.

+
+example a heap as an array +
example a heap as an array
+
+

Insertion

+

Basically add the new element at the end of the heap. Then look it's parent if it is smaller or bigger depends on the whether it is max-heap or min-heap (max-heap called when Parents are always greater), swap with the parent. If it is swapped do the same operation for the parent.

+

Deletion

+

If you are going to delete a node (root node or another one does not matter),

+
    +
  1. Swap the node to be deleted with the last element of heap to maintain a balanced structure.
  2. +
  3. Delete the last element which is the node we want to delete at the start.
  4. +
  5. Now you have a node which is in the wrong place, You have to find the correct place for the swapped last element, to do this starting point you should check its left and right children, if one them is greater than our node you should swap it with the greatest child(or smallest if it is min-heap).
  6. +
  7. Still current node may in the wrong place, so apply Step 3 as long as it is not greater than its children(or smaller if it is min-heap).
  8. +
+
+ + +
an example deletion on a heap structure
+
+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
class BinHeap:
+    def __init__(self):
+        self.heapList = [0]
+        self.currentSize = 0
+
+    def percUp(self,i):
+        while i // 2 > 0:
+            if self.heapList[i] < self.heapList[i // 2]:
+                tmp = self.heapList[i // 2]
+                self.heapList[i // 2] = self.heapList[i]
+                self.heapList[i] = tmp
+            i = i // 2
+
+    def insert(self,k):
+        self.heapList.append(k)
+        self.currentSize = self.currentSize + 1
+        self.percUp(self.currentSize)
+
+    def percDown(self,i):
+        while (i * 2) <= self.currentSize:
+            mc = self.minChild(i)
+            if self.heapList[i] > self.heapList[mc]:
+                tmp = self.heapList[i]
+                self.heapList[i] = self.heapList[mc]
+                self.heapList[mc] = tmp
+            i = mc
+
+    def minChild(self,i):
+        if i * 2 + 1 > self.currentSize:
+            return i * 2
+        else:
+            if self.heapList[i*2] < self.heapList[i*2+1]:
+                return i * 2
+            else:
+                return i * 2 + 1
+
+    def delMin(self):
+        retval = self.heapList[1]
+        self.heapList[1] = self.heapList[self.currentSize]
+        self.currentSize = self.currentSize - 1
+        self.heapList.pop()
+        self.percDown(1)
+        return retval
+
+    def buildHeap(self,alist):
+        i = len(alist) // 2
+        self.currentSize = len(alist)
+        self.heapList = [0] + alist[:]
+        while (i > 0):
+            self.percDown(i)
+            i = i - 1
+
+bh = BinHeap()
+bh.buildHeap([9,5,6,2,3])
+
+print(bh.delMin())
+print(bh.delMin())
+print(bh.delMin())
+print(bh.delMin())
+print(bh.delMin())
+
+

Complexity

+

Insertion \(\mathcal{O}(logN)\), delete-min \(\mathcal{O}(logN)\) , and finding minimum \(\mathcal{O}(1)\). These operations depend on heap's height and heaps are always complete binary trees, basically the height is \(logN\). (N is number of Node)

+

Priority Queue

+

Priority queues are a type of container adaptors, specifically designed so that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.

+

While priority queues are often implemented with heaps, they are conceptually distinct from heaps. A priority queue is an abstract concept like "a list" or "a map"; just as a list can be implemented with a linked list or an array, a priority queue can be implemented with a heap or a variety of other methods such as an unordered array.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
#include <iostream>       // std::cout
+#include <queue>          // std::priority_queue
+using namespace std;
+int main () {
+    priority_queue<int> mypq;
+
+    mypq.push(30);
+    mypq.push(100);
+    mypq.push(25);
+    mypq.push(40);
+
+    cout << "Popping out elements...";
+    while (!mypq.empty()) {
+        cout << ' ' << mypq.top();
+        mypq.pop();
+    }
+    return 0;
+}
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/04-graph-1/LateX/360px-Max-Heap.png b/graph/img/360px-Max-Heap.png similarity index 100% rename from bundles/04-graph-1/LateX/360px-Max-Heap.png rename to graph/img/360px-Max-Heap.png diff --git a/bundles/04-graph-1/LateX/Heap-as-array.png b/graph/img/Heap-as-array.png similarity index 100% rename from bundles/04-graph-1/LateX/Heap-as-array.png rename to graph/img/Heap-as-array.png diff --git a/docs/graph/img/bfs.jpg b/graph/img/bfs.jpg similarity index 100% rename from docs/graph/img/bfs.jpg rename to graph/img/bfs.jpg diff --git a/bundles/11-graph-3/latex/biconnectivity.png b/graph/img/biconnectivity.png similarity index 100% rename from bundles/11-graph-3/latex/biconnectivity.png rename to graph/img/biconnectivity.png diff --git a/bundles/04-graph-1/LateX/binary-tree.png b/graph/img/binary-tree.png similarity index 100% rename from bundles/04-graph-1/LateX/binary-tree.png rename to graph/img/binary-tree.png diff --git a/bundles/04-graph-1/LateX/binarytree.png b/graph/img/binarytree.png similarity index 100% rename from bundles/04-graph-1/LateX/binarytree.png rename to graph/img/binarytree.png diff --git a/bundles/07-graph-2/latex/bipartite.png b/graph/img/bipartite.png similarity index 100% rename from bundles/07-graph-2/latex/bipartite.png rename to graph/img/bipartite.png diff --git a/bundles/07-graph-2/latex/bipartite_check.png b/graph/img/bipartite_check.png similarity index 100% rename from bundles/07-graph-2/latex/bipartite_check.png rename to graph/img/bipartite_check.png diff --git a/docs/graph/img/cut-point.png b/graph/img/cut-point.png similarity index 100% rename from docs/graph/img/cut-point.png rename to graph/img/cut-point.png diff --git a/bundles/07-graph-2/latex/dag.png b/graph/img/dag.png similarity index 100% rename from bundles/07-graph-2/latex/dag.png rename to graph/img/dag.png diff --git a/docs/graph/img/dfs.jpg b/graph/img/dfs.jpg similarity index 100% rename from docs/graph/img/dfs.jpg rename to graph/img/dfs.jpg diff --git a/docs/graph/img/directed_acyclic_graph.png b/graph/img/directed_acyclic_graph.png similarity index 100% rename from docs/graph/img/directed_acyclic_graph.png rename to graph/img/directed_acyclic_graph.png diff --git a/docs/graph/img/first-flow.png b/graph/img/first-flow.png similarity index 100% rename from docs/graph/img/first-flow.png rename to graph/img/first-flow.png diff --git a/bundles/11-graph-3/latex/flow1.png b/graph/img/flow1.png similarity index 100% rename from bundles/11-graph-3/latex/flow1.png rename to graph/img/flow1.png diff --git a/bundles/11-graph-3/latex/flow2.png b/graph/img/flow2.png similarity index 100% rename from bundles/11-graph-3/latex/flow2.png rename to graph/img/flow2.png diff --git a/bundles/11-graph-3/latex/flow3.png b/graph/img/flow3.png similarity index 100% rename from bundles/11-graph-3/latex/flow3.png rename to graph/img/flow3.png diff --git a/bundles/11-graph-3/latex/flow4.png b/graph/img/flow4.png similarity index 100% rename from bundles/11-graph-3/latex/flow4.png rename to graph/img/flow4.png diff --git a/bundles/11-graph-3/latex/flow5.png b/graph/img/flow5.png similarity index 100% rename from bundles/11-graph-3/latex/flow5.png rename to graph/img/flow5.png diff --git a/bundles/04-graph-1/LateX/heap1.png b/graph/img/heap1.png similarity index 100% rename from bundles/04-graph-1/LateX/heap1.png rename to graph/img/heap1.png diff --git a/bundles/04-graph-1/LateX/heap2.png b/graph/img/heap2.png similarity index 100% rename from bundles/04-graph-1/LateX/heap2.png rename to graph/img/heap2.png diff --git a/bundles/07-graph-2/latex/kruskal.jpg b/graph/img/kruskal.jpg similarity index 100% rename from bundles/07-graph-2/latex/kruskal.jpg rename to graph/img/kruskal.jpg diff --git a/bundles/07-graph-2/latex/mst.png b/graph/img/mst.png similarity index 100% rename from bundles/07-graph-2/latex/mst.png rename to graph/img/mst.png diff --git a/bundles/07-graph-2/latex/prim.png b/graph/img/prim.png similarity index 100% rename from bundles/07-graph-2/latex/prim.png rename to graph/img/prim.png diff --git a/docs/graph/img/scc-graph.png b/graph/img/scc-graph.png similarity index 100% rename from docs/graph/img/scc-graph.png rename to graph/img/scc-graph.png diff --git a/docs/graph/img/scc.png b/graph/img/scc.png similarity index 100% rename from docs/graph/img/scc.png rename to graph/img/scc.png diff --git a/bundles/07-graph-2/latex/shortest.png b/graph/img/shortest.png similarity index 100% rename from bundles/07-graph-2/latex/shortest.png rename to graph/img/shortest.png diff --git a/bundles/07-graph-2/latex/toporder.png b/graph/img/toporder.png similarity index 100% rename from bundles/07-graph-2/latex/toporder.png rename to graph/img/toporder.png diff --git a/bundles/07-graph-2/latex/tree-def.png b/graph/img/tree-def.png similarity index 100% rename from bundles/07-graph-2/latex/tree-def.png rename to graph/img/tree-def.png diff --git a/docs/graph/img/types-of-edges.png b/graph/img/types-of-edges.png similarity index 100% rename from docs/graph/img/types-of-edges.png rename to graph/img/types-of-edges.png diff --git a/graph/index.html b/graph/index.html new file mode 100644 index 0000000..c50b20e --- /dev/null +++ b/graph/index.html @@ -0,0 +1,1029 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Graph - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/introduction/index.html b/graph/introduction/index.html new file mode 100644 index 0000000..223d24e --- /dev/null +++ b/graph/introduction/index.html @@ -0,0 +1,610 @@ + + + + + + + + + + + + + + + + + + + + + Introduction - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Introduction + +

+ +
+ + +

A graph is a structure amounting to a set of objects in which some pairs of the objects are in some sense "related". The objects correspond to the mathematical abstractions called vertices (also called nodes or points) and each of the related pairs of vertices is called an edge. Typically, a graph is depicted in diagrammatic form as a set of dots for the vertices, joined by lines for the edges. [8]

+

Why graphs? Graphs are usually used to represent different elements that are somehow related to each other.

+

A Graph consists of a finite set of vertices(or nodes) and set of edges which connect a pair of nodes. G = (V,E)

+

V = set of nodes

+

E = set of edges(e) represented as e = a,b

+

Graph are used to show a relation between objects. So, some graphs may have directional edges (e.g. people and their love relationships that are not mutual: Alice may love Alex, while Alex is not in love with her and so on), and some graphs may have weighted edges (e.g. people and their relationship in the instance of a debt)

+
+Directed Acyclic Graph +
Figure 1: a simple unweigted graph
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/max-flow/index.html b/graph/max-flow/index.html new file mode 100644 index 0000000..b43111b --- /dev/null +++ b/graph/max-flow/index.html @@ -0,0 +1,789 @@ + + + + + + + + + + + + + + + + + + + + + Max Flow - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Max Flow + +

+ +
+ + +

Flow Network

+

A flow network is a special type of directed graph that contains a single source and a single target node. In a flow network, each edge has a capacity, which indicates the maximum amount of flow that can pass through that edge.

+
+One of the earliest examples of a flow network in history. +
One of the earliest examples of a flow network in history.
+
+

Maximum Flow

+

Maximum flow is an algorithm that calculates the maximum amount of flow that can reach the target from the source in a flow network while maintaining a continuous flow.

+

There are several algorithms to solve the Maximum Flow problem. The time complexities of some popular ones are:

+
    +
  • Ford-Fulkerson algorithm: \(\mathcal{O}(E * \text{flowCount})\)
  • +
  • Edmonds-Karp algorithm: \(\mathcal{O}(V * E^2)\)
  • +
  • Dinic's algorithm: \(\mathcal{O}(E * V^2)\)
  • +
+

Where V is the number of vertices and E is the number of edges in the flow network.

+

Ford Fulkerson

+

The steps of the Ford-Fulkerson maximum flow algorithm are as follows:

+
    +
  • Find a path from the source to the target.
  • +
  • The edge with the minimum capacity in the found path determines the flow that can pass through this path.
  • +
  • Decrease the capacities of the edges in the path by the flow amount (the minimum capacity found in step 2) and add the reverse edges to the graph with a capacity equal to the flow.
  • +
  • Repeat until there are no more paths from the source to the target.
  • +
+

Why does this algorithm work?

+

For example, let's assume we find a flow of size x through an edge from u to v.

+

Suppose the path we found is \(a \rightarrow ... \rightarrow u \rightarrow v \rightarrow ... \rightarrow b\).

+

We will add a new edge from v to u with a capacity of x to our graph, but this newly added reverse edge does not exist in the original graph.

+

After adding the reverse edges, the new path we find might look like \(c \rightarrow ... \rightarrow v \rightarrow u \rightarrow ... \rightarrow d\), with a flow of size y.

+

It is clear that \(y \leq x\).

+

We can represent three different valid flows as follows:

+
    +
  • A flow of size y following the path \(a \rightarrow ... \rightarrow u \rightarrow ... \rightarrow d\)
  • +
  • A flow of size y following the path \(c \rightarrow ... \rightarrow u \rightarrow ... \rightarrow b\)
  • +
  • A flow of size x - y following the path \(a \rightarrow ... \rightarrow u \rightarrow v \rightarrow ... \rightarrow d\)
  • +
+

The overall time complexity of the Ford-Fulkerson algorithm is \(\mathcal{O}(E * \text{flowCount})\) because, in the worst case, each found path increases the flow by only 1. Since finding each path takes time proportional to the number of edges, the complexity becomes \(\mathcal{O}(E * \text{flowCount})\).

+

However, if we implement the Ford-Fulkerson algorithm using BFS, the complexity changes. In this case, for every edge, the flows that consider this edge as the bottleneck will continually increase, leading to a time complexity of \(\mathcal{O}(V * E^2)\). This specific implementation is known as the Edmonds-Karp Algorithm.

+
+The figure on the left shows how much flow is passing through each edge. The figure on the right represents the current state of the graph. +
The figure on the left shows how much flow is passing through each edge. The figure on the right represents the current state of the graph.
+
+
+Flow = 7 +
Flow = 7
+
+
+Flow = 8 +
Flow = 8
+
+
+Flow = 13 +
Flow = 13
+
+
+Flow = 15 +
Flow = 15
+
+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
// c matrix holds the capacities of the edges.
+// g adjacency list allows us to traverse the graph.
+bool bfs() {
+    vector<bool> visited(n, false);
+    queue<int> q;
+    q.push(source);
+    visited[source] = true;
+    while (!q.empty()) {
+        int node = q.front();
+        q.pop();
+        if (node == sink)
+            break;
+        for (int i = 0; i < g[node].size(); i++) {
+            int child = g[node][i];
+            if (c[node][child] <= 0 or visited[child])
+                continue;
+            visited[child] = true;
+            parent[child] = node;
+            q.push(child);
+        }
+    }
+    return visited[sink];
+}
+int max_flow() {
+    while (bfs()) {
+        int curFlow = -1, node = sink;
+        while (node != source) {
+            // curFlow is the minimum capacity in the current path, i.e. the flow we found.
+            int len = c[parent[node]][node];
+            if (curFlow == -1)
+                curFlow = len;
+            else
+                curFlow = min(curFlow, len);
+            node = parent[node];
+        }
+        flow += curFlow;
+        node = sink;
+        while (node != source) {
+            c[parent[node]][node] -= curFlow;
+            // We are subtracting the flow we found from the path we found.
+            c[node][parent[node]] += curFlow;  // We are adding the reverses of the edges
+            node = parent[node];
+        }
+    }
+    return flow;
+}
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/minimum-spanning-tree/index.html b/graph/minimum-spanning-tree/index.html new file mode 100644 index 0000000..c274870 --- /dev/null +++ b/graph/minimum-spanning-tree/index.html @@ -0,0 +1,751 @@ + + + + + + + + + + + + + + + + + + + + + Minimum Spanning Tree - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Minimum Spanning Tree + +

+ +
+ + +

Definition

+

Given an undirected weighted connected graph \(G = (V,E)\) Spanning tree of G is a connected acyclic sub graph that covers all nodes and some edges. In a disconnected graph -where there is more than one connected component- the spanning tree of that graph is defined as the forest of the spanning trees of each connected component of the graph.

+

Minimum spanning tree (MST) is a spanning tree in which the sum of edge weights is minimum. The MST of a graph is not unique in general, there might be more than one spanning tree with the same minimum cost. For example, take a graph where all edges have the same weight, then any spanning tree would be a minimum spanning tree. In problems involving minimum spanning trees where you have to output the tree itself (and not just the minimum cost), it either puts more constraint so the answer is unique, or simply asks for any minimum spanning tree.

+
+Minimum Spanning Tree +
MST of the graph. It spans all nodes of the graph and it is connected.
+
+

To find the minimum spanning tree of a graph, we will introduce two algorithms. The first one called Prim's algorithm, which is similar to Dijkstra's algorithm. Another algorithm is Kruskal agorithm, which makes use of the disjoint set data structure. Let's discover each one of them in detail!

+

Prim Algorithm

+

Prim algorithm is very similar to Dijkstra's shortest path algorithm. In this algorithm we have a set \(S\) which represents the explored nodes and again we can maintain a priority queue data structure the closest node in \(V-S\). It is a greedy algorithm just like Dijkstra's shortest path algorithm.

+
+
1
+2
+3
+4
+5
+6
+7
+8
G = (V, E)   V set of all nodes, E set of all edges
+T = {}       result, edges of MST
+S = {1}      explored nodes
+while S /= V do
+    let (u, v) be the lowest cost edge such that u in S and v in V - S;
+    T = T U {(u, v)}
+    S = S U {v}
+end
+
+
Prim Algorithm in Pseudo code, what is the problem here?
+
+

There is a problem with this implementation, it assumes that the graph is connected. If the graph is not connected this algorithm will be stuck on loop. There is a good visualization for Prim algorithm at [10]. If we use priority queue complexity would be \(O(ElogV)\).

+
+Prim's Algorithm +
Example of how Prim Algorithm constructs the MST
+
+

Kruskal Algorithm

+

In Prim algorithm we started with a specific node and then proceeded with choosing the closest neighbor node to our current graph. In Kruskal algorithm, we follow a different strategy; we start building our MST by choosing one edge at a time, and link our (intially separated) nodes together until we connect all of the graph.

+

To achieve this task, we will start with having all the nodes separated each in a group. In addition, we will have the list of edges from the original graph sorted based on their cost. At each step, we will:

+
    +
  1. Pick the smallest available edge (that is not taken yet)
  2. +
  3. Link the nodes it connects together, by merging their group into one unified group
  4. +
  5. Add the cost of the edge to our answer
  6. +
+

However, you may realize in some cases the link we add will connect two nodes from the same group (because they were grouped before by other taken edges), hence violating the spanning tree condition (Acyclic) and more importantly introducing unnecessary edges that adds more cost to the answer. So to solve this problem, we will only add the edges as long as they connect two currently (at the time of processing this edge) separated nodes that belong to different groups, hence completing the algorithm.

+

The optimality of Kruskal algorithm comes from the fact that we are taking from a sorted list of edges. For more rigorous proof please refer to [11].

+

So how can we effectively merge the group of nodes and check that which group each node belong? We can utilize disjoint set data structure which will help us to make union and find operations in an amortized constant \(\mathcal{O}(1)\) time.

+
 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
+26
+27
+28
+29
+30
typedef pair<int,pair<int,int>> edge;
+// represent edge as triplet (w,u,v)
+// w is weigth, u and v verticies.
+// edge.first is weigth edge.second.first -> u, edge.second.second -> v
+typedef vector<edge> weigthed_graph;
+
+/*union - find data structure utilities */
+const int maxN = 3005;
+int parent[maxN];
+int ssize[maxN];
+void make_set(int v);
+int find_set(int v);
+void union_sets(int a, int b);
+void init_union_find();
+
+/*Code that finds edges in MST */
+void kruskal(vector<edge> &edgeList ){
+    vector<edge> mst;
+    init_union_find();
+    sort(edgeList.begin(),edgeList.end(), \
+        [](const auto &a, const auto  &b) { return a.first< b.first;}); 
+    //well this weird syntax is lambda function 
+    // for sorting pairs to respect their first element.
+    for( auto e: edgeList){
+        if( find_set(e.second.first )!= find_set(e.second.second)){
+            mst.push_back(e);
+            union_sets(e.second.first, e.second.second);
+        }
+    }
+}
+
+

To calculate the time complexity, observe how we first sorted the edges, this takes \(\mathcal{O}(E log E)\). In addition we pass through the edges one by one, and each time we check which group the two nodes of the edge belongs to, and in some cases merge the two groups. So in the worst case we will assume that both operations (finding and merging) happens, but since the disjoint data structure guarantee \(\mathcal{O}(1)\) amortized time for both operations, we end up with \(\mathcal{O}(E)\) amortized time of processing the nodes.

+

So in total we have \(\mathcal{O}(E log E)\) from sorting edges and \(\mathcal{O}(E)\) from processing them, those results in a total of \(\mathcal{O}(E log E)\) (if you don't understand why please refer to the first bundle where we discuss time complexity).

+
+Kruskal's Algorithm +
Example of how Kruskal Algorithm constructs the MST
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/representing-graphs/index.html b/graph/representing-graphs/index.html new file mode 100644 index 0000000..0b07e84 --- /dev/null +++ b/graph/representing-graphs/index.html @@ -0,0 +1,763 @@ + + + + + + + + + + + + + + + + + + + + + Representing Graphs - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Representing Graphs + +

+ +
+ + +

Edge Lists

+

A simple way to define edge list is that it has a list of pairs. We just have a list of objects consisting of the vertex numbers of 2 nodes and other attributes like weight or the direction of edges. [16]

+
    +
  • + For some specific algorithms you need to iterate over all the edges, (i.e. kruskal's algorithm)
  • +
  • + All edges are stored exactly once.
  • +
  • - It is hard to determine whether two nodes are connected or not.
  • +
  • - It is hard to get information about the edges of a specific vertex.
  • +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
#include <iostream>
+#include <vector>
+using namespace std;
+
+int main(){
+    int edge_number;
+    vector<pair <int,int> > edges;
+    cin >> edge_number;
+    for( int i=0 ; i<edge_number ; i++ ){
+        int a,b;
+        cin >> a >> b;
+        edges.push_back(make_pair(a,b)); // a struct can be used if edges are weighted or have other properties.
+    }
+}
+
+

Adjacency Matrices

+

Stores edges, in a 2-D matrix. matrix[a][b] keeps an information about road from a to b. [16] +- + We can easily check if there is a road between two vertices. +- - Looping through all edges of a specific node is expensive because you have to check all of the empty cells too. Also these empty cells takes huge memory in a graph which has many vertices. (For example representing a tree)

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
#include <iostream>
+#include <vector>
+using namespace std;
+int main(){
+    int node_number;
+    vector<vector<int> > Matrix;
+    cin >> node_number;
+    for( int i=0 ; i<node_number ; i++ )
+        for( int j=0 ; j<node_number ; j++ ){
+            Matrix.push_back(vector <int> ());
+            int weight;
+            cin >>weight ;
+            Matrix[i].push_back(weight);
+        }
+}
+
+

Adjacency List

+

Each node has a list consisting of nodes each is adjacent to. So, there will be no empty cells. Memory will be equal to number of edges. The most used one is in algorithms. [16]

+
    +
  • + You do not have to use space for empty cells.
  • +
  • + Easily iterate over all the neighbors of a specific node.
  • +
  • - If you want to check if two nodes are connected, in this form you still need to iterate over all the neighbors of one of them. But, there are some structures that you can do this operation in O(log N). For example if you won't add any edge, you can sort every vector with nodes' names, so you can find it by binary search.
  • +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
#include <iostream>
+#include <vector>
+using namespace std;
+
+int main(){
+    int node_number,path_number;
+
+    vector<vector<int> > paths; 
+    // use object instead of int, 
+    //if you need to store other features
+
+    cin >> node_number >> path_number;
+    for( int i=0 ; i<node_number ; i++ )
+        Matrix.push_back(vector <int> ());
+    for( int j=0 ; j< path_number ; j++ ){
+        int beginning_node, end_node;
+        cin >> beginning_node >> end_node;
+
+        Matrix[ beginning_node ].push_back( end_node ); // push st
+        // Matrix[ end_node ].push_back(  beginning_node ); 
+        // ^^^ If edges are Undirected, you should push in reverse direction too
+    }
+}
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/shortest-path/index.html b/graph/shortest-path/index.html new file mode 100644 index 0000000..ecb6a01 --- /dev/null +++ b/graph/shortest-path/index.html @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + Shortest Path Problem - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Shortest Path Problem + +

+ +
+ + +

Definition

+

Let \(G(V,E)\) be a graph, \(v_i\) and \(v_j\) be two nodes of \(G\). We say a path between \(v_i\) and \(v_j\) is the shortest path if sum of the edge weights (cost) in the path is minimum. In other words, the shortest path problem is the problem of finding a path between two vertices (or nodes) in a graph such that the sum of the weights of its constituent edges is minimized. [5]

+
+Shortest Path +
Example shortest path in graph. Source is A and target is F. Image taken from [5].
+
+

We will cover several shortest path algorithms in this bundle. One of them is Dijkstra’s Shortest Path Algorithm but it has some drawbacks: Edge weights should be non-negative for the optimally of the algorithm. We will discover other algorithms in which these condition isn’t necessary, like Floyd-Warshall and Bellman-Ford algorithms.

+

Dijkstra's Shortest Path Algorithm

+

Dijkstra’s Shortest Path algorithm is straight forward. In brief we have a set \(S\) that contains explored nodes and \(d\) which contains the shortest path cost from source to another node. In other words, \(d(u)\) represents the shortest path cost from source to node \(u\). The procedure follows as that. First, add source node to set \(S\) which represents the explored nodes and assigns the minimum cost of the source to zero. Then each iteration we add node to \(S\) that has lowest cost \((d(u))\) from unexplored nodes. Let’s say \(S′ = V − S\) which means unexplored nodes. For all nodes in \(S′\) we calculate \(d(x)\) for each node \(x\) is \(S′\) then we pick minimum cost node and add it to \(S\). So how we calculate \(d(x)\)? For any \(x\) node from \(S′\), \(d(x)\) calculated as that, let’s say \(e\) cost of any edge from \(S\) to \(x\) then \(d(x) = min(d(u) + e)\). It is a greedy algorithm.

+

Here is the explanation of the algorithm step by step.

+
    +
  1. +

    Initialize an empty set, distance array, insert source to set.

    +
  2. +
  3. +

    Initialize a min-heap, put source to heap with key is zero.

    +
  4. +
  5. +

    While heap is not empty, take the top element from heap and add its neighbours to min-heap.

    +
  6. +
  7. +

    Once we pick an element from the heap, it is guaranteed that the same node will never be added to heap with lower key value.

    +
  8. +
+

In implementation we can use priority queue data structure in order to increase efficiency. If we put unexplored nodes to min - priority queue where the distance is key, we can take the lowest cost unexplored node in \(O(log(n))\) time which is efficient.

+
 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
+26
+27
+28
+29
+30
+31
typedef pair<int,int> edge;
+typedef vector<edge> adjList;
+typedef vector<adjList> graph;
+
+void dijkstra(graph &g, int s) {
+    vector<int> dist(g.size(),INT_MAX/2);
+    vector<bool> visited(g.size(),false);
+
+    dist[s] = 0;
+
+    priority_queue<edge, vector<edge>, greater<edge>> q;
+    q.push({0, s});
+
+    while(!q.empty()) {
+        int v = q.top().second;
+        int d = q.top().first;
+        q.pop();
+
+        if(visited[v]) continue;
+        visited[v] = true;
+
+        for(auto it: g[v]) {
+            int u = it.first;
+            int w = it.second;
+            if(dist[v] + w < dist[u]) {
+                dist[u] = dist[v] + w;
+                q.push({dist[u], u});
+            } 
+        }       
+    }
+}
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/strong-connectivity-and-biconnectivity/index.html b/graph/strong-connectivity-and-biconnectivity/index.html new file mode 100644 index 0000000..c94d9eb --- /dev/null +++ b/graph/strong-connectivity-and-biconnectivity/index.html @@ -0,0 +1,641 @@ + + + + + + + + + + + + + + + + + + + + + Strong Connectivity and Biconnectivity - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Strong Connectivity and Biconnectivity + +

+ +
+ + +

Strong Connectivity

+

To reach a target node from a given node, it must be possible to arrive at the target by passing through a finite number of nodes.

+

In an undirected graph, if every node is reachable from every other node, the graph is called connected. When the same concept is applied to directed graphs, it is called strongly connected.

+

In other words, for a directed graph to be strongly connected, it must be possible to reach every other node from any given node.

+

Biconnectivity

+

In an undirected graph, if the remaining graph remains connected when any node is removed, the graph is called biconnected. In other words, if the graph has no articulation points, it is considered a biconnected graph.

+
+An example of biconnected graph +
An example of biconnected graph
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/strongly-connected-components/index.html b/graph/strongly-connected-components/index.html new file mode 100644 index 0000000..8f00b00 --- /dev/null +++ b/graph/strongly-connected-components/index.html @@ -0,0 +1,686 @@ + + + + + + + + + + + + + + + + + + + + + Strongly Connected Components - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Strongly Connected Components + +

+ +
+ + +

All directed graphs can be divided into disjoint subgraphs that are strongly connected. For two subgraphs to be disjoint, they must not share any common edges or nodes. If we consider each of these resulting subgraphs as a single node and create a new graph, the resulting graph will be a directed acyclic graph (DAG), meaning it will have no cycles.

+
+The subgraphs marked in red are the strongly connected components. +
The subgraphs marked in red are the strongly connected components.
+
+
+The newly formed graph, created by treating each strongly connected component as a single node, results in a directed acyclic graph (DAG), meaning it contains no cycles. +
The newly formed graph, created by treating each strongly connected component as a single node, results in a directed acyclic graph (DAG), meaning it contains no cycles.
+
+

Tarjan's Algorithm for finding strongly connected components (SCCs) in a directed graph (An alternative approach is Kosaraju's Algorithm, but Tarjan's algorithm is often preferred in practice due to its speed and simpler understanding):

+
    +
  • Start traversing the graph using DFS order from any node and push the visited nodes onto a stack. Calculate the discovery time for each node. (Discovery time is the time unit when the node is first reached during DFS traversal, and we will call this the index.)
  • +
  • If a node is in the stack, it is not yet part of any strongly connected component. This is because, when a strongly connected component is found, all the nodes belonging to that component are removed from the stack.
  • +
  • For each node, calculate the index of the node that has the minimum index among the nodes reachable from the current node and its subtree through edges that do not belong to any strongly connected component. This value is called the "minimum reachable depth" from the subtree of the node (also known as the "low" value).
  • +
  • If a node's low value is equal to its own index, then this node and all nodes below it in the stack form a strongly connected component. This is because if we call this node "u," there must be an edge from u's subtree back to u itself. Otherwise, u's low value would be clearly smaller than its own index.
  • +
  • When a strongly connected component is found (as explained in the previous step), remove all nodes belonging to this component from the stack.
  • +
+

Using Tarjan's Algorithm, we can find all strongly connected components in a graph with a time complexity of \(\mathcal{O}(V + E)\), where \(V\) is the number of vertices and \(E\) is the number of edges.

+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
void dfs(int node) {
+    low[node] = index[node] = ++curTime;
+    // curTime holds the discovery time of each node.
+    used[node] = true;
+
+    st.push(node);
+    inStack[node] = true;
+    // inStack holds whether a node is in the stack or not.
+    for (auto it : g[node]) {
+        if (!used[it]) {
+            dfs(it);
+            low[node] = min(low[node], low[it]);
+        } else if (inStack[it])
+            low[node] = min(low[node], index[it]);
+        // If the adjacent node is in the stack, then this edge can be a back edge.
+    }
+    if (low[node] == index[node]) {
+        while (1) {
+            int x = st.top();
+            st.pop();
+            cout << x << " ";
+            inStack[x] = false;
+            if (x == node)
+                break;
+        }
+        cout << endl;
+    }
+}
+
+void scc() {
+    for (int i = 0; i < n; i++)
+        if (!used[i])
+            dfs(i);
+}
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/topological-sort/index.html b/graph/topological-sort/index.html new file mode 100644 index 0000000..7440ae8 --- /dev/null +++ b/graph/topological-sort/index.html @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + + + + + + Topological Sort - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Topological Sort + +

+ +
+ + +

Definition

+

Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u->v, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG [6].

+

There are many important usages of topological sorting in computer science; applications of this type arise in instruction scheduling, ordering of formula cell evaluation when recomputing formula values in spreadsheets, logic synthesis, determining the order of compilation tasks to perform in makefiles, data serialization, and resolving symbol dependencies in linkers. It is also used to decide in which order to load tables with foreign keys in databases [7].

+

There are known algorithms (e.g Kahn’s algorithm) to find topological order in linear time. Below, you can find one of the implementations:

+
+Topological Order +
For example, a topological sorting of this graph is “5 4 2 3 1 0”. There can be more than one topological sorting for a graph. For example, another topological sorting of the following graph is “4 5 2 3 1 0”. The first vertex in topological sorting is always a vertex with in-degree as 0 (a vertex with no incoming edges)[6].
+
+

Algorithm

+
 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
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
typedef vector<int> adjList;
+typedef vector<adjList> graph;
+typedef pair<int,int> ii;
+
+void kahn(graph &g) {
+    vector<int> result;
+    queue<int> q;
+    vector<int> degree(g.size(),0); // number of incoming egdes.
+    for(auto &list: g){
+        for(auto &node:list) {
+            degree[node]++;
+        } 
+    }
+
+    for(int i=0; i < g.size(); ++i) {
+        if (degree[i] == 0)
+        q.push(i);
+    }
+
+    while( !q.empty()) {
+        int node = q.front();
+        result.push_back(node);
+        q.pop();
+
+        for (auto &ng: g[node]) {
+            degree[ng]--;
+            if (degree[ng] == 0)
+                q.push(ng); 
+        }
+    }
+
+    for(auto &i:result)
+        cout << i << " ";
+    cout << endl;
+}
+int main(){
+    graph g(6);
+    g[1].push_back(0);
+    g[1].push_back(2);
+    g[2].push_back(3);
+    g[3].push_back(4);
+    g[4].push_back(5);
+    kahn(g);
+    return 0; 
+}
+
+

As for time complexity: we traverse all edges in the beginning (calculating degrees) and in the while segment we remove edges (once for an edge) and traverse all nodes. Hence, the time complexity of this algorithm is \(O(V +E)\). Note that this implementation assumes the graph is DAG. Try improving this code to support checking if the graph is DAG!

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/tree-traversals/index.html b/graph/tree-traversals/index.html new file mode 100644 index 0000000..f613640 --- /dev/null +++ b/graph/tree-traversals/index.html @@ -0,0 +1,734 @@ + + + + + + + + + + + + + + + + + + + + + Tree Traversals - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Tree Traversals + +

+ +
+ + +

The tree traversal is the process of visiting every node exactly once in a tree structure for some purposes(like getting information or updating information). In a binary tree there are some described order to travel, these are specific for binary trees but they may be generalized to other trees and even graphs as well.

+
+a binary tree +
a binary tree
+
+

Preorder Traversal

+

Preorder means that a root will be evaluated before its children. In other words the order of evaluation is: Root-Left-Right

+
1
+2
+3
+4
Preorder Traversal
+    Look Data
+    Traverse the left node
+    Traverse the right node
+
+

Example: 50 – 7 – 3 – 2 – 8 – 16 – 5 – 12 – 17 – 54 – 9 – 13

+

Inorder Traversal

+

Inorder means that the left child (and all of the left child’s children) will be evaluated before the root and before the right child and its children. Left-Root-Right (by the way, in binary search tree inorder retrieves data in sorted order)

+
1
+2
+3
+4
Inorder Traversal
+    Traverse the left node
+    Look Data
+    Traverse the right node 
+
+

Example: 2 – 3 – 7 – 16 – 8 – 50 – 12 – 54 – 17 – 5 – 9 – 13

+

Postorder Traversal

+

Postorder is the opposite of preorder, all children are evaluated before their root: Left-Right-Root

+
1
+2
+3
+4
Postorder Traversal
+    Traverse the left node
+    Traverse the right node 
+    Look Data
+
+

Example: 2 – 3 – 16 – 8 – 7 – 54 – 17 – 12 – 13 – 9 – 5 – 50

+

Implementation

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
class Node:
+    def __init__(self,key):
+        self.left = None
+        self.right = None
+        self.val = key
+
+def printInorder(root):
+    if root:
+        printInorder(root.left)
+        print(root.val)
+        printInorder(root.right)
+
+def printPostorder(root):
+    if root:
+        printPostorder(root.left)
+        printPostorder(root.right)
+        print(root.val)
+
+def printPreorder(root):
+    if root:
+        print(root.val)
+        printPreorder(root.left)
+        printPreorder(root.right)
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graph/union-find/index.html b/graph/union-find/index.html new file mode 100644 index 0000000..1c03d55 --- /dev/null +++ b/graph/union-find/index.html @@ -0,0 +1,689 @@ + + + + + + + + + + + + + + + + + + + + + Union Find - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Union Find + +

+ +
+ + +

A disjoint-set data structure is a data structure that keeps track of a set of elements partitioned into a number of disjoint (non-overlapping) subsets. A union-find algorithm is an algorithm that performs two useful operations on such a data structure: [11, 12]

+
    +
  • Find: Determine which subset a particular element is in. This can be used for determining if two elements are in the same subset.
  • +
  • Union: Join two subsets into a single subset
  • +
  • Union-Find Algorithm can be used to check whether an undirected graph contains cycle or not. This is another method based on Union-Find. This method assumes that graph doesn’t contain any self-loops.
  • +
  • Most commonly used in kruskal's minumum spanning tree algorithm, it is used to check whether two nodes are in same connected component or not. [10]
  • +
+

Implementation

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
#include <bits/stdc++.h>
+using namespace std;
+
+cont int MaxN=100005; // Max number of nodes
+
+int ancestor[MaxN];
+
+int parent(int k) // return the ancestor
+{
+    if(ancestor[k]==k) return k;
+    return ancestor[k] = parent(ancestor[k]); 
+    // do not forget to equlize ancestor[k], it is going to decrease time complexity for the next operations
+}
+
+int MakeUnion(int a,int b) // setting parent of root(a) as root(b).
+{
+    a = parent(a);
+    b= parent(b);
+    ancestor[a] = b;
+}
+int find(int a,int b)
+{
+    return parent(a)==parent(b);
+}
+
+

Complexity

+

Using both path compression, splitting, or halving and union by rank or size ensures that the amortized time per operation is only \(\mathcal{O}(\alpha (n))\), which is optimal, where \(\alpha (n)\) is the inverse Ackermann function. This function has a value \(\alpha (n)<5\) for any value of n that can be written in this physical universe, so the disjoint-set operations take place in essentially constant time.

+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guidelines/Document Writing Guideline.pdf b/guidelines/Document Writing Guideline.pdf deleted file mode 100644 index 558dd4b..0000000 Binary files a/guidelines/Document Writing Guideline.pdf and /dev/null differ diff --git a/guidelines/Preparation Flow.pdf b/guidelines/Preparation Flow.pdf deleted file mode 100644 index 44319d7..0000000 Binary files a/guidelines/Preparation Flow.pdf and /dev/null differ diff --git a/guidelines/Problem Selecting Guideline.pdf b/guidelines/Problem Selecting Guideline.pdf deleted file mode 100644 index c6faa09..0000000 Binary files a/guidelines/Problem Selecting Guideline.pdf and /dev/null differ diff --git a/guidelines/Review Guideline.pdf b/guidelines/Review Guideline.pdf deleted file mode 100644 index 5b1ad0f..0000000 Binary files a/guidelines/Review Guideline.pdf and /dev/null differ diff --git a/guidelines/latex/template/README.md b/guidelines/latex/template/README.md deleted file mode 100644 index e8b158f..0000000 --- a/guidelines/latex/template/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Algorithm-Competition-Programme LaTeX Template - -## Quickstart - -To quickly start using the LaTeX template for either creating new bundle or editing the existing ones, you can create a new project in [Overleaf](https://overleaf.com) and import the LaTeX files there. - -Instead of using an online environment, if you want to compile the template locally, you should download and install **Pygments** in order to work on this template. - -For any problem or question, you can send a mail to contact@inzva.com \ No newline at end of file diff --git a/guidelines/latex/template/inzva-logo.png b/guidelines/latex/template/inzva-logo.png deleted file mode 100644 index c044253..0000000 Binary files a/guidelines/latex/template/inzva-logo.png and /dev/null differ diff --git a/guidelines/latex/template/template.pdf b/guidelines/latex/template/template.pdf deleted file mode 100644 index caeebbf..0000000 Binary files a/guidelines/latex/template/template.pdf and /dev/null differ diff --git a/guidelines/latex/template/template.tex b/guidelines/latex/template/template.tex deleted file mode 100644 index 38870fe..0000000 --- a/guidelines/latex/template/template.tex +++ /dev/null @@ -1,278 +0,0 @@ -\documentclass[12pt]{article} -\usepackage[utf8]{inputenc} -\usepackage{lmodern} -\usepackage[T1]{fontenc} -\usepackage{amsmath} -\usepackage{enumitem} -\usepackage{graphicx} -\usepackage{fullpage} -\usepackage{siunitx} -\usepackage{fancyhdr} -\PassOptionsToPackage{hyphens}{url} -\usepackage[hyphens]{url} -\usepackage{color} -\usepackage{enumitem} -\usepackage{textcomp} -\usepackage{geometry} -\usepackage{courier} -\usepackage{listings} -\usepackage{array} -\usepackage{amsthm} -\usepackage{mathdots} -\usepackage{amssymb} -\usepackage{minted} -\usepackage{wrapfig} -\usepackage{titlesec} -\usepackage{parskip} -\usepackage{accents} -\usepackage{gensymb} -\usepackage{indentfirst} -\usepackage{courier} -\usepackage{framed} -\usepackage{etoolbox} -\usepackage{titlesec} -\usepackage{appendix} -\usepackage{mdframed} -\usepackage{verbatim} -\usepackage{xspace} -\usepackage{hyperref} -\AtBeginEnvironment{subappendices}{% - \section*{Appendix} - \addcontentsline{toc}{section}{Appendices} -} - -%\lstset{language=C++, -% basicstyle=\ttfamily, -% keywordstyle=\color{blue}\ttfamily, -% stringstyle=\color{red}\ttfamily, -% commentstyle=\color{green}\ttfamily, -% morecomment=[l][\color{magenta}]{\#} -%} - -\definecolor{keywordcolor}{rgb}{0,0,0.45} -\definecolor{stringcolor}{rgb}{0.45,0.45,0.45} -\definecolor{commentcolor}{rgb}{0,0.3,0} - -\lstset{ - language=C++, - basicstyle=\footnotesize\ttfamily, - numbers=left, - %numberstyle=\tiny, - frame=tb, - columns=fullflexible, - showstringspaces=false, - breaklines=true, - tabsize=4, - keywordstyle=\color{keywordcolor}\footnotesize\bf\ttfamily, - stringstyle=\color{stringcolor}\footnotesize\ttfamily, - commentstyle=\color{commentcolor}\it\sffamily -} -% \lstset{basicstyle=\ttfamily,breaklines=true} -\lstloadlanguages{C++} - -%\renewcommand{\familydefault}{\sfdefault} - -\addtolength{\parskip}{\baselineskip} -\newcommand{\urlwofont}[1]{\urlstyle{same}\url{#1}} - -\renewcommand{\arraystretch}{0.8} -\renewcommand{\headrulewidth}{0pt} -\renewcommand{\footrulewidth}{0pt} - -\newcommand{\imagewidth}{0.8\textwidth} - -\lhead{} -\chead{} -\rhead{} -\lfoot{} -\cfoot{\thepage} -\rfoot{} - -\geometry{ - top=0.9in, - inner=0.7in, - outer=0.7in, - bottom=0.9in, - headheight=2ex, - headsep=1ex, -} -\pagestyle{fancy} -%\fancyhf{} -%\setlength{\headsep}{0.2in} - - -\fancypagestyle{firststyle} -{ - \chead{} - \setlength{\headsep}{0.0in} -} -\hypersetup{ - unicode=true, - colorlinks=true, - linkcolor=blue, - citecolor=black, - filecolor=black, - urlcolor=blue -} - -\begingroup -\makeatletter -\@for\theoremstyle:=definition,remark,plain\do{% - \expandafter\g@addto@macro\csname th@\theoremstyle\endcsname{% - \addtolength\thm@preskip\parskip - }% -} -\endgroup - -\newtheorem{thm}{Theorem}[section] -\newtheorem{lemma}{Lemma}[section] -\newtheorem{claim}{Claim}[section] -\newtheorem{proposition}{Proposition}[section] -%\theoremstyle{empty} -\newtheorem*{namedthm}{Theorem} - -% indention size -%\setlength{\parindent}{19pt} -\setlength{\parindent}{0pt} - -% paragraph spacing -\setlength{\parskip}{1em} - -% line spacing -\linespread{1} - -%\setcounter{tocdepth}{1} - - -% Documenting starts here! Please do not change above! - -\newcommand{\mytitle} -{ - \textbf { - inzva Algorithm Programme 2018-2019\\ \ \\ - Bundle 2 \\ \ \\ - Algorithms - 1 \\ \ \\ - } -} - -\title{\vspace{-2em}\mytitle\vspace{-0.3em}} - -\author{ - \textbf{Editor}\\ - Editor's Name \\ \ \\ - \textbf{Reviewers} \\ - Reviewer's Name\\ - Reviewer's Name -} - -\date{} -\begin{document} - - \begin{figure} - \centering - \includegraphics[width=\linewidth/4]{inzva-logo.png} - \label{fig:inzva} - \end{figure} - \maketitle - - \cleardoublepage - \tableofcontents - \markboth{Table of Contents}{} - \cleardoublepage - - \section{Basics} - - \subsection{Listing} - - A list example from intro-1 document: - \begin{itemize} - \item \texttt{ls} - list files in current directory. Usage: \texttt{ls} - \item \texttt{cd} - change directory. Usage: \texttt{cd \textasciitilde/Desktop}. - \item \texttt{mkdir} - make a new directory. Usage: \texttt{mkdir directory\_name} - \item \texttt{mv} - move command(cut). Usage: \texttt{mv source\_path destination\_path}. - \item \texttt{cp} - copy command. Usage: \texttt{cp source\_path destination\_path} - \item \texttt{rm} - remove command. Usage: \texttt{rm file\_path} - \end{itemize} - - \subsection{Links and References} - - Link to \href{https://inzva.com}{inzva} web page. - - "A computer would deserve to be called intelligent if it could deceive a human into believing that it was human."\cite{turing} - - \subsection{Pages} - - After this points, we can clear the remaining part of the page with \textbf{cleardoublepage} command - - \cleardoublepage - - \section{Codes and Math} - - \subsection{Codes} - - \subsubsection{C++} - -\begin{minted}[frame=lines,linenos,fontsize=\footnotesize]{c++} -int fibonacci( int n ){ - - int result = 1, previous = 1; - - for( int i=2 ; i<=n ; i++ ){ - int tmp = result; - result += previous; - previous = tmp; - } - - return result; -} -\end{minted} - - \subsubsection{Python} - -\begin{minted}[frame=lines,linenos,fontsize=\footnotesize]{python} -class Fraction: - - def __init__(self, numerator, denominator): - self.numerator, self.denominator = numerator, denominator - - def bigFraction(a, b): - - if a.numerator * b.denominator > a.denominator * b.numerator: - return a - - return b - -a, b = Fraction(15, 20), Fraction(12, 18) # Create two Fractions in order to compare them -biggest = bigFraction(a, b) - -print(biggest.numerator, biggest.denominator) -\end{minted} - - \cleardoublepage - - \subsection{Mathematical Formulas} - - You can write mathematical formulas between \$ symbols. Examples: - - $\frac{f(x+h) - f(x)}{h}$, \ $[2, \sqrt{N}]$, \ $h\sum_{i=1}^{r}i^{2}$, \ $f(x) = x^{\dfrac{3}{5+x}}\cdot(x-20)$ - - You can use double \$ for formatting: - - $$\int_{0}^{2}f(x)dx = (c + 0.2*2 + 12.5*2^2 + 2^3) - (c + 0.2*0 + 12.5*0^2 + 0^3) = 58.4$$ - - \subsubsection{Functions With Cases} - - \begin{align*} - f(n) &= \begin{cases} - 1 & \text{if $n = 0$ or $n = 1$\,\, } \\ - f(n - 1) + f(n - 2) & \text{if $n > 1$\,\,} - \end{cases} - \end{align*} - - \begin{thebibliography}{0} - - \bibitem{turing} - "Computing Machinery and Intelligence". Book by Alan Turing, 1950. - \end{thebibliography} - -\end{document} diff --git a/index.html b/index.html new file mode 100644 index 0000000..f570014 --- /dev/null +++ b/index.html @@ -0,0 +1,707 @@ + + + + + + + + + + + + + + + + + + + + + + + Algorithm Program - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Algorithm Program + +

+ +
+ + +

Algoritm Program contains lectures about algorithms and data structures which are prepared by inzva community, aimed at teaching advanced knowledge of algorithms to university students, spreading algorithmic thinking and providing training which will help them in international contests as well as in their professional lives.

+

There is also a video playlist in Turkish about some of the algorithms and data structures in YouTube:

+ + +

How to Use This Site

+
    +
  • Lectures can be found by topics at the navigation bar. The sub topics can be found at those pages. Search bar is also available for finding pages by terms.
  • +
  • In each lecture related problems and training sets from algoleague.com are mentioned. Practicing those is highly recommended.
  • +
+

How to Contribute

+

In order to contribute (adding new lecture, fixing any type of errors) below steps should be followed:

+
    +
  1. Create an issue and briefly explain the purpose of your contribution.
  2. +
  3. Fork the repository with your personal account and apply your changes.
  4. +
  5. Create a pull request to master branch and add the link of pull request to issue.
  6. +
  7. After reviewing your pull request and discussion, your pull request will be merged. Thank you for your contribution!
  8. +
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/introduction/index.html b/introduction/index.html new file mode 100644 index 0000000..42ad086 --- /dev/null +++ b/introduction/index.html @@ -0,0 +1,1859 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Introduction - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + +

+ + Introduction + +

+ +
+ + +

Editor: Muhammed Burak Buğrul

+

Reviewers: Kadir Emre Oto & Yusuf Hakan Kalaycı

+

Introduction

+

First of all, this is an intensive algorithm programme prepared by inzva, which includes lectures, contests, problem-solvings and a variety of practises. "Competitive Programming" term will be mentioned frequently in this programme, especially for it's community, help in progress in algorithms and data structures etc.

+

Just for a quick cover up we will have a look at what happens when you compile and run a program, basic data types and functions. After that, we will examine C++ Standard Template Library(STL), time complexity and memory space.

+

Command Line

+

A lot of people don't use command line if they can use an alternative. There are powerful IDEs (Integrated Development Environments) and they really make programming easier in some aspects. However, knowing how to use command line is important, especially for competitive programming. Firstly, it gives a low level knowledge and full control; secondly, every computer and environment has command line interface.

+

In this document, you will find only a basic introduction to the command line, which is no more than the basic usage of a file system, compiler, and programs.

+

There are a lot of differences between command line of Windows and Linux. But the differences between those of Mac and Linux are less.

+

Linux and Mac

+

Mac users can use the built-in Terminal. You can find it by searching from Spotlight. Linux users can use gnome-terminal or any other installed one. Again, you can find them by using the built-in search tab.

+

Some basic commands:

+
    +
  • ls list files in current directory. Usage: ls
  • +
  • cd change directory. Usage: cd ~/Desktop
  • +
  • mkdir make a new directory. Usage: mkdir directory_name
  • +
  • mv move command (cut). Usage: mv source_path destination_path
  • +
  • cp copy command. Usage: cp source_path destination_path
  • +
  • rm remove command. Usage: rm file_path
  • +
+

You can read more about the unix command line at: http://linuxcommand.org

+

Compiling and Executing Programs

+

G++

+

G++ is installed in Linux environments but in Mac, you should install Xcode first.

+

You can compile your cpp souce file by typing g++ source.cpp. Default output of this command is a.out.

+

Running Executable Files

+

For Linux and Mac, the command to run a program is ./program_name. If you use default g++ command, the name of your program will be a.out, so you should type ./a.out in order to run it.

+

Closing a Program

+

When you want to kill a program in running step, you can simply hit Control + C.

+

When you want to suspend a program in running step, you can simply hit Control + Z.

+

When you want to register EOF on standart input, you can simply hit Control + D.

+

Input/Output Redirection

+

You can redirect input and output streams of a program by using command line and it is surprisingly easy.

+

Saving Output to a File

+

The only thing you need is > symbol. Just add it at the end of your run command with the output file name: ./a.out > output.txt

+

Note: This redirection process creates output.txt if it doesn't exist; otherwise deletes all content in it, then writes into it. If you want to use > in appending mode you should use >> instead.

+

Reading Input from a File

+

It is almost the same as output file redirection. The symbol is < now. Usage: ./a.out < input.txt

+

This will make your job easier than copying and pasting input to test your program, especially in the contests.

+

Using Both at the Same Time

+

One of the wonderful things about these redirections is that they can be used at the same time. You can simply add both to the end of your run command: ./a.out < input.txt > output.txt

+

pipe

+

Sometimes, you may want to redirect the output of a program to another program as input. You can use the | symbol for this. Usage: ./program1 | ./program2

+

diff

+

As the name denotes, it can check two files line by line if they are the same or not. If not, it outputs different lines. Usage: diff file1.txt file2.txt

+

It is very useful for comparing output of brute force solution and real solution.

+

Structs and Classes

+

In almost every programming language, you can define your own data type. C++ has structs, classes; Python has dictionaries, classes etc. You can think of them as packets that store more than one different data and implement functions at the simplest level. They have a lot more abilities than these two (You can check OOP out).

+

Let us examine a fraction struct written in C++.

+

We need to store two values for a fraction, numerator and denominator.

+
1
+2
+3
struct Fraction {
+  int numerator, denominator;
+};
+
+

This is the simplest definition of a struct. Fraction struct contains two int variables. We call them members. So, Fraction struct has two members called numerator and denominator.

+
 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
+26
+27
+28
+29
+30
#include <cstdio>
+
+struct Fraction {
+    int numerator, denominator;
+};
+
+Fraction bigFraction(Fraction a, Fraction b) {
+
+    if( a.numerator * b.denominator > a.denominator * b.numerator )
+        return a;
+
+    return b;
+}
+
+int main() {
+    // Create two Fractions in order to compare them
+    Fraction a, b;
+
+    a.numerator = 15;
+    a.denominator = 20;
+
+    b.numerator = 12;
+    b.denominator = 18;
+
+    // Create a new Fraction in order to store biggest of Fraction a and Fraction b.
+    fraction biggest = bigFraction(a, b);
+
+    printf("The biggest fraction is %d / %d\n", biggest.numerator, biggest.denominator);
+    return 0;
+}
+
+

Let us do the same in Python3:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
class Fraction:
+
+    def __init__(self, numerator, denominator):
+        self.numerator, self.denominator = numerator, denominator
+
+def bigFraction(a, b):
+
+    if a.numerator * b.denominator > a.denominator * b.numerator:
+        return a
+
+    return b
+
+a, b = Fraction(15, 20), Fraction(12, 18)  # Create two Fractions in order to compare them
+biggest = bigFraction(a, b)
+
+print(biggest.numerator, biggest.denominator)
+
+

In the sample codes above, a, b and biggest are called objects of Fraction. Also, the word instance can be used instead of object.

+

The Arrow Operator (C++)

+

Sometimes, usage of struct can change in C++. When you have a pointer to a struct, you should use -> to access its members instead of . operator. If you still want to use . operator, you should do in this way: (*ptr).member. But arrow operator is simpler: ptr->member.

+

Big O Notation

+

When dealing with algorithms or coming up with a solution, we need to calculate how fast our algorithm or solution is. We can calculate this in terms of number of operations. Big \(\mathcal{O}\) notation moves in exactly at this point. Big \(\mathcal{O}\) notation gives an upper limit to these number of operations. The formal definition of Big \(\mathcal{O}\) is [1].

+

Let \(f\) be a real or complex valued function and \(g\) a real valued function, both defined on some unbounded subset of the real positive numbers, such that \(g(x)\) is strictly positive for all large enough values of \(x\). One writes:

+

\[f(x) = \mathcal{O}{(g(x))} \ as\ x \rightarrow \infty\]

+

If and only if for all sufficiently large values of x, the absolute value of \(f(x)\) is at most a positive constant multiple of \(g(x)\). That is, \(f(x)\) = \(\mathcal{O}{(g(x))}\) if and only if there exists a positive real number \(M\) and a real number \(x_0\) such that:

+

\[|f(x)| \leq Mg(x)\ for \ all\ x\ such\ that\ x_0 \leq x\]

+

In many contexts, the assumption that we are interested in the growth rate as the variable \(x\) goes to infinity is left unstated, and one writes more simply that:

+

\[f(x) = \mathcal{O}(g(x))\]

+

Almost every case for competitive programming, basic understanding of Big \(\mathcal{O}\) notation is enough to decide whether to implement a solution or not.

+

Note: Big \(\mathcal{O}\) notation can be used for calculating both the run time complexity and the memory space used.

+

Recursion

+

Recursion occurs when functions repeat themselves in order to create repeated applications or solve a problem by handling smaller situations first. There are thousands of examples in mathematics. One of the simple ones is factorial of \(n\). It can be shown by \(n!\) in mathematics and it gives the product of all positive integers from \(1\) to \(n\), for example, \(4! = 1\cdot 2\cdot 3\cdot 4 = 24\). If we write factorial in a mathematical way, it will be:

+

\[ +\begin{align*} + f(n) &= \begin{cases} + 1 & \text{if $n = 0$\,\, } \\ + n \cdot f(n - 1) & \text{if $n > 0$\,\,} + \end{cases} +\end{align*} +\]

+

The reason why we didn't simply write it as \(f(n) = n \cdot f(n-1)\) is that it doesn't give sufficient information about function. We should know where to end the function calls, otherwise it can call itself infinitely. Ending condition is \(n = 0\) here. We call it base case. Every recursive function needs at least one base case.

+

So if we write every step of \(f(4)\), it will be:

+

\[ +\begin{align*} + 4! + &= 4\cdot f(3) && \text{recursive step} \\ + &= 4\cdot 3\cdot f(2) && \text{recursive step} \\ + &= 4\cdot 3\cdot 2\cdot f(1) && \text{recursive step} \\ + &= 4\cdot 3\cdot 2\cdot 1\cdot f(0) && \text{recursive step} \\ + &= 4\cdot 3\cdot 2\cdot 1\cdot 1 && \text{base case} \\ + &= 24 && \text{arithmetic} +\end{align*} +\]

+

Basically, we can apply this recursive logic into programming:

+
1
+2
+3
+4
+5
+6
int factorial(int n) {
+    int result = 1;
+    for(int i = 1; i <= n; i++)
+        res *= i;
+    return result;
+}
+
+

We can say a function is a recursive if it calls itself. Let us change this iterative factorial function into a recursive one. When you imagine how the recursive code will look like, you will notice it will look like the mathematical one:

+
1
+2
+3
+4
+5
int factorial(int n) {
+    if(n == 0)
+        return 1;
+    return n * factorial(n - 1);
+}
+
+

Note that we didn't forget to put our base case into the recursive function implementation.

+

Time Complexity

+

In case above, it can be seen that both recursive and iterative implementations of factorial function runs in \(\mathcal{O}{(n)}\) time. But this equality doesn't occur always. Let us examine fibonacci function, it is mathematically defines as:

+

\[ +\begin{align*} + f(n) &= \begin{cases} + 1 & \text{if $n = 0$ or $n = 1$\,\, } \\ + f(n - 1) + f(n - 2) & \text{if $n > 1$\,\,} + \end{cases} +\end{align*} +\]

+

We can implement this function with just one for loop:

+
1
+2
+3
+4
+5
+6
+7
+8
+9
int fibonacci(int n) {
+    int result = 1, previous = 1;
+    for (int i = 2; i <= n; i++) {
+        int tmp = result;
+        result += previous;
+        previous = tmp;
+    }
+    return result;
+}
+
+

Again, we can implement recursive one according to the mathematical formula:

+
1
+2
+3
+4
+5
int fibonacci(int n) {
+    if( n == 0 || n == 1 )
+        return 1;
+    return fibonacci(n - 1) + fibonacci(n - 2);
+}
+
+

Let us calculate time complexity of iterative one. There are three basic operations inside a for loop that repeats \(n-2\) times. So time complexity is \(\mathcal{O}(n)\). But what about the recursive one? Let us examine its recursion tree(diagram of function calls) for \(n = 5\) on visualgo.

+

\(f\) function called more than one for some values of n. Actually in every level, number of function calls doubles. So time complexity of the recursive implementation is \(\mathcal{O}{(2^n)}\). It is far away worse than the iterative one. Recursive one can be optimized by techniques like memoization, but it is another topic to learn in further weeks.

+

Mutual Recursion

+

Mutual recursion occurs when functions call each other. For example function f calls another function g, which also somehow calls f again.

+

Note: When using mutual recursions in C++, don't forget to declare one of the functions so that the other function can know first one from its' prototype.

+

Note 2: You can chain more than two functions and it will be still a mutual recursion.

+

Enumeration and Brute-Force

+

Enumeration is numbering method on a set.

+

For example, permutation is one of enumeration techniques. First permutation of numbers in range \(1\) and \(n\) is:

+

\[1, 2, 3... n-1, n\]

+

And second one is:

+

\[1, 2, 3... n, n-1\]

+

Finally, the last one is:

+

\[n, n-1... 3, 2, 1\]

+

Additionally, we can try to enumerate all possible distributions of \(n\) elements into 3 different sets. An example of a distribution of 5 elements can be represented as:

+

\[1, 1, 2, 1, 3\]

+

In this distribution the first, the second and the fourth elements goes into the first set; third element goes into second set and the last element goes into the third set.

+

Enumerations can be done with recursive functions easily. We will provide example implementations of 3-set one. But before examining recursive implementation, let us try to implement iterative one:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
#include <cstdio>
+
+int main(){
+
+    for( int i=1 ; i<=3 ; i++ )
+        for( int j=1 ; j<=3 ; j++ )
+            for( int k=1 ; k<=3 ; k++ )
+                for( int l=1 ; l<=3 ; l++ )
+                    for( int m=1 ; m<=3 ; m++ )
+                        printf("%d %d %d %d %d\n", i, j, k, l, m);
+
+    return 0;
+}
+
+

It will print all possible distributions of 5 elements into 3 sets. But what if we had 6 elements? Yes, we should have added another for loop. What if we had \(n\) elements? We can not add infinite number of for loops. But we can apply same logic with recursive functions easily:

+
 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
#include <cstdio>
+
+int ar[100];
+
+void enumerate( int element, int n ){
+
+    if( element > n ){ // Base case
+
+        for( int i=1 ; i<=n ; i++ )
+            printf("%d ", ar[i]);
+
+        printf("\n");
+        return;
+    }
+
+    for( int i=1 ; i<=3 ; i++ ){
+        ar[element] = i;
+        enumerate(element + 1, n);
+    }
+}
+
+int main(){
+    enumerate(1, 5);
+    return 0;
+}
+
+

Brute-Force is trying all cases in order to achieve something(searching best, shortest, cheapest etc.).

+

One of the simplest examples of brute-forces approaches is primality checking. We know that for a prime \(P\) there is no positive integer in range \([2, P-1]\) that evenly divides \(P\). We can simply check all integers in this range to decide if it is prime:

+
1
+2
+3
+4
+5
+6
bool isPrime(int N) {
+    for( int i=2 ; i<N ; i++ )
+        if( N % i == 0 )
+            return false;
+    return true;
+}
+
+

It is a simple function, but its' time complexity is \(\mathcal{O}(N)\). Instead we can benefit from the fact if there is a positive integer \(x\) that evenly divides \(N\), there is a positive integer \(\frac{N}{x}\) as well. As we know this fact, we can only check the integer in range \([2, \sqrt{N}]\):

+
1
+2
+3
+4
+5
+6
bool isPrime(int N) {
+    for( int i=2 ; i*i <= N ; i++ )
+        if( N % i == 0 )
+            return false;
+    return true;
+}
+
+

Now, its' time complexity is \(\mathcal{O}{(\sqrt{N})}\). It is far away better than \(\mathcal{O}{(N)}\).

+

Built-In Data Structures and Functions

+

There is no need to reinvent the wheel. Every language has its' own built in data structures, functions etc. After this point, the document will be C++ centered. But Python alternatives will be given.

+

The C++ Standard Template Library (STL)

+

The STL is a well known library for C++ that includes variety of data structures and algorithms.

+

Note: Third party libraries generally not allowed in contests.

+

Pairs

+

C++: Sometimes you may need to store two elements for an object. We can do this by creating a struct/class or two dimensional array. They will all work well but using pairs will be much more easier. You can think of pair as a class that has two variables named first and second. That's all for the basic. The good part is, you can decide their types(int, double, your own struct/class etc.). An example for pairs in C++:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
#include <iostream>
+
+using namespace std;
+
+int main(){
+
+    pair<int, int> p(1, 2);
+    pair<int, string> p2;
+
+    p2.first = 3;
+    p2.second = "Hey there!";
+
+    pair<pair<int, string>, string> nested;
+
+    nested.first = p2;
+    nested.second = "This is a nested one";
+
+    cout << "Info of p -> " << p.first << " " << p.second << endl;
+    cout << "Info of p2 -> " << p2.first << " " << p2.second << endl;
+    cout << "Info of nested -> " << nested.first.first << " " << nested.first.second
+            << " " << nested.second << endl;
+
+    return 0;
+}
+
+

Python: You can simply create a tuple or an array:

+
1
+2
+3
+4
+5
+6
+7
+8
p = (1, 2)
+p2 = [1, "Hey there!"]
+nested = ((3, "inner?"), "outer", "this is a tuple you can add more")
+
+p2[0] = 3
+# nested[0] = "don't"  # In python you can't change tuples, but you can change arrays
+
+print(p, p2, nested)
+
+

Vectors

+

C++: When using array, we should decide its size. What if we don't have to do this, what if we could add elements into it without considering the current size? Well, all these ideas take us to vectors.

+

C++ has this structure. Its name is vector. It is a dynamic array but you don't have to think about its size. You can simply add elements into it. Like pairs, you can use it with any type (int, double, another vector, your struct/class etc.). Usage of a vector is very similar to classic array:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
#include <iostream>
+#include <vector>
+
+using namespace std;
+
+int main(){
+
+    vector<int> ar;
+
+    for( int i=0 ; i<10 ; i++ )
+        ar.push_back(i);
+
+    for( int i=0 ; i<(int)ar.size() ; i++ )
+        cout << ar[i] << " ";
+
+    cout << endl;
+    return 0;
+}
+
+

Python: Python lists already behave like vectors:

+
1
+2
+3
+4
+5
+6
ar = []
+
+for i in range(10):
+    ar.append(i)
+
+print(ar)
+
+

Stacks, Queues, and Deques

+

C++: They are no different than stack, queue and deque we already know. It provides the implementation, you can simply include the libraries and use them. See queue, stack, deque.

+

Priority Queues

+

It is basically a built-in heap structure. You can add an element in \(\mathcal{O}(logN)\) time, get the first item in \(O(logN)\) time. The first item will be decided according to your choice of priority. This priority can be magnitude of value, enterence time etc.

+

C++: The different thing for priority queue is you should add #include <queue>, not <priority_queue>. You can find samples here. Again, you can define a priority queue with any type you want.

+

Note: Default priority_queue prioritizes elements by highest value first. Here is three ways of defining priority.

+

Python: You can use heapq in python.

+

Sets and Maps

+

C++: Now that we mentioned binary trees (heap above), we can continue on built-in self balanced binary trees. Sets are key collections, and maps are key-value collections. Sets are useful when you want to add/remove elements in \(\mathcal{O}(logN)\) time and also check existence of an item(key) in \(O(logN)\) time. Maps basically do the same but you can change value associated to a key without changing the position of the key in the tree. You can check c++ references for set and map. You can define them with any type you want. If you want to use them with your own struct/class, you must implement a compare function.

+

Python: You can use dictionaries for map and sets for set in python without importing any other libraries.

+

Iterators

+

C++: You can use iterators for every built-in data structure in C++ for pointing their objects.

+

Python: You can iterate through any iterable in python by using in. You can check this example.

+

Sorting

+

C++: In almost every language, there is a built-in sort function. C++ has one as well. It runs in \(\mathcal{O}(N log N)\) time. You can pass your own compare function into sort function of C++.

+

Python: You can use sort function for any list or list like collection in order to sort them or if you don't want to change the original collection, you can use sorted() function instead. You can pass your own compare function into sort function of python by using key variable.

+

Suggested Readings

+

C++

+ +

Python

+ +

References

+
    +
  1. Landau, Edmund (1909). Handbuch der Lehre von der Verteilung der Primzahlen [Handbook on the theory of the distribution of the primes] (in German). Leipzig: B. G. Teubner. p. 31.
  2. +
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index c40f875..0000000 --- a/mkdocs.yml +++ /dev/null @@ -1,90 +0,0 @@ -site_name: Algorithm Program -site_url: https://inzva.github.io/Algorithm-Program/ -nav: - - Home: index.md - - Introduction: introduction/index.md - - Data Structures: data-structures/index.md - - Algorithms: algorithms/index.md - - Graph: graph/index.md - - Dynamic Programming: dynamic-programming/index.md -theme: - name: material - custom_dir: docs/overrides - favicon: static/img/favicon.png - logo: static/img/logo.png - features: - - toc.follow - - navigation.tabs - - search.suggest - - search.highlight - - content.tabs.link - - content.code.annotation - - content.code.copy - language: en - palette: - - scheme: default - toggle: - icon: material/weather-night - name: Switch to dark mode - primary: black - accent: grey - - scheme: slate - toggle: - icon: material/weather-sunny - name: Switch to light mode - primary: black - accent: white - -extra: - social: - - icon: fontawesome/brands/github-alt - link: https://github.com/inzva - - icon: fontawesome/brands/twitter - link: https://twitter.com/inzvaspace - - icon: fontawesome/brands/instagram - link: https://instagram.com/inzva.space/ - - icon: fontawesome/brands/linkedin - link: https://linkedin.com/company/inzva/ - -extra_javascript: - - static/javascripts/katex.js - - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/katex.min.js - - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/contrib/auto-render.min.js - -extra_css: - - static/stylesheets/main.css - - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/katex.min.css - -markdown_extensions: - - pymdownx.highlight: - linenums: true - anchor_linenums: true - - pymdownx.inlinehilite - - pymdownx.snippets - - admonition - - pymdownx.arithmatex: - generic: true - block_tag: "p" - - footnotes - - pymdownx.details - - pymdownx.superfences: - custom_fences: - - name: mermaid - class: mermaid - format: !!python/name:pymdownx.superfences.fence_code_format - - pymdownx.mark - - attr_list - - pymdownx.emoji: - emoji_index: !!python/name:material.extensions.emoji.twemoji - emoji_generator: !!python/name:material.extensions.emoji.to_svg - - toc: - permalink: true - - md_in_html - - tables - -plugins: - - search - - tags - -copyright: | - © 2024 inzva diff --git a/docs/overrides/partials/content.html b/overrides/partials/content.html similarity index 100% rename from docs/overrides/partials/content.html rename to overrides/partials/content.html diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..3634b7a --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Algorithm Program","text":"

Algoritm Program contains lectures about algorithms and data structures which are prepared by inzva community, aimed at teaching advanced knowledge of algorithms to university students, spreading algorithmic thinking and providing training which will help them in international contests as well as in their professional lives.

There is also a video playlist in Turkish about some of the algorithms and data structures in YouTube:

"},{"location":"#how-to-use-this-site","title":"How to Use This Site","text":"
  • Lectures can be found by topics at the navigation bar. The sub topics can be found at those pages. Search bar is also available for finding pages by terms.
  • In each lecture related problems and training sets from algoleague.com are mentioned. Practicing those is highly recommended.
"},{"location":"#how-to-contribute","title":"How to Contribute","text":"

In order to contribute (adding new lecture, fixing any type of errors) below steps should be followed:

  1. Create an issue and briefly explain the purpose of your contribution.
  2. Fork the repository with your personal account and apply your changes.
  3. Create a pull request to master branch and add the link of pull request to issue.
  4. After reviewing your pull request and discussion, your pull request will be merged. Thank you for your contribution!
"},{"location":"algorithms/","title":"Algorithms","text":"

Editor: Kadir Emre Oto

Reviewers: Muhammed Burak Bu\u011frul, Tahsin Enes Kuru

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#search-algorithms","title":"Search Algorithms","text":"

It may be necessary to determine if an array or solution set contains a specific data, and we call this finding proccess searching. In this article, three most common search algorithms will be discussed: linear search, binary search, and ternary search.

This visualization may help you understand how the search algorithms work.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#linear-search","title":"Linear Search","text":"

Simplest search algorithm is linear search, also know as sequential search. In this technique, all elements in the collection of the data is checked one by one, if any element matches, algorithm returns the index; otherwise, it returns \\(-1\\).

Its time complexity is \\(\\mathcal{O}(N)\\).

Example for linear search
int linearSearch(int *array, int size, int key) {\n    for (int i = 0; i < size; i++)\n        if (array[i] == key)\n            return i;\n    return -1;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#binary-search","title":"Binary Search","text":"

We know linear search is quite a slow algorithm because it compares each element of the set with search key, and there is a high-speed searching technique for sorted data instead of linear search, which is binary search. After each comparison, the algorithm eliminates half of the data using the sorting property.

We can also use binary search on increasing functions in the same way.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure","title":"Procedure","text":"
  1. Compare the key with the middle element of the array,
  2. If it is a match, return the index of middle.
  3. If the key is bigger than the middle, it means that the key must be in the right side of the middle. We can eliminate the left side.
  4. If the key is smaller, it should be on the left side. The right side can be ignored.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(\\tfrac{N}{2}\\right) + \\mathcal{O}(1) \\\\ T(N) &= \\mathcal{O}(\\log N) \\end{align*} \\]

Example for binary search
int binarySearch(int *array, int size, int key) {\n    int left = 0, right = size, mid;\n\n    while (left < right) {\n        mid = (left + right) / 2;\n\n        if (array[mid] >= key)\n            right = mid;\n        else\n            left = mid + 1;\n    }\n    return array[left] == key ? left : -1;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#ternary-search","title":"Ternary Search","text":"

Suppose that we have a unimodal function, \\(f(x)\\), on an interval \\([l, r]\\), and we are asked to find the local minimum or the local maximum value of the function according to the behavior of it.

There are two types of unimodal functions:

  1. The function, \\(f(x)\\) strictly increases for \\(x \\leq m\\), reaches a global maximum at \\(x = m\\), and then strictly decreases for \\(m \\leq x\\). There are no other local maxima.

  2. The function, \\(f(x)\\) strictly decreases for \\(x \\leq m\\), reaches a global minimum at \\(x = m\\), and then strictly increases for \\(m \\leq x\\). There are no other local minima.

In this document, we will implement the first type of unimodal function, and the second one can be solved using the same logic.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_1","title":"Procedure","text":"
  1. Choose any two points \\(m_1\\), and \\(m_2\\) on the interval \\([l, r]\\), where \\(l < m_1 < m_2 < r\\).
  2. If \\(f(m_1) < f(m_2)\\), it means the maxima should be in the interval \\([m_1, r]\\), so we can ignore the interval \\([l, m_1]\\), move \\(l\\) to \\(m_1\\)
  3. Otherwise, \\(f(m_1) \\geq f(m_2)\\), the maxima have to be in the interval \\([l, m_2]\\), move \\(r\\) to \\(m_2\\)
  4. If \\(r - l < \\epsilon\\), where \\(\\epsilon\\) is a negligible value, stop the algorithm, return \\(l\\). Otherwise turn to the step 1.

\\(m_1\\) and \\(m_2\\) can be selected by \\(m_1 = l + \\frac{r-l}{3}\\) and \\(m_2 = r - \\frac{r-l}{3}\\) to avoid increasing the time complexity.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_1","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(2 \\cdot \\tfrac{N}{3}\\right) + \\mathcal{O}(1) \\\\ T(N) &= \\mathcal{O}(\\log N) \\end{align*} \\]

Example for ternary search
double f(double x);\n\ndouble ternarySearch(double left, double right, double eps = 1e-7) {\n    while (right - left > eps) {\n        double mid1 = left + (right - left) / 3;\n        double mid2 = right - (right - left) / 3;\n\n        if (f(mid1) < f(mid2))\n            left = mid1;\n        else\n            right = mid2;\n    }\n    return f(left);\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#sorting-algorithms","title":"Sorting Algorithms","text":"

Sorting algorithms are used to put the elements of an array in a certain order according to the comparison operator. Numerical order or lexicographical orders are the most common ones, and there are a large number of sorting algorithms, but we discuss four of them:

  • Insertion Sort
  • Merge Sort
  • Quick Sort
  • Radix Sort

For a better understanding, you are strongly recommended to go into this visualization site after reading the topics.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#insertion-sort","title":"Insertion Sort","text":"

Think that you are playing a card game and want to sort them before the game. Your sorting strategy is simple: you have already sorted some part and every time you pick up the next card from unsorted part, you insert it into the correct place in sorted part. After you apply this process to all cards, the whole deck would be sorted.

This is the basic idea for sorting an array. We assume that the first element of the array is the sorted part, and other elements are in the unsorted part. Now, we choose the leftmost element of the unsorted part, and put it into the sorted part. In this way the left part of the array always remains sorted after every iteration, and when no element is left in the unsorted part, the array will be sorted.

void insertionSort(int *ar, int size) {\n    for (int i = 1; i < size; i++)\n        for (int j = i - 1; 0 <= j and ar[j] > ar[j + 1]; j--)\n            swap(ar[j], ar[j + 1]);\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#merge-sort","title":"Merge Sort","text":"

Merge Sort is one of the fastest sorting algorithms that uses Divide and Conquer paradigm. The algorithm divides the array into two halves, solves each part recursively using same sorting function and combines them in linear time by selecting the smallest value of the arrays every time.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_2","title":"Procedure","text":"
  1. If the size of the array is 1, it is sorted already, stop the algorithm (base case),
  2. Find the middle point of the array, and split it in two,
  3. Do the algorithm for these parts separately from the first step,
  4. After the two halves got sorted, merge them in linear time and the array will be sorted.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_2","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(\\tfrac{N}{2}\\right) + \\mathcal{O}(N) \\\\ T(N) &= \\mathcal{O}(N \\cdot \\log N) \\end{align*} \\]

void mergeSort(int *ar, int size) {\n    if (size <= 1) // base case\n        return;\n\n    mergeSort(ar, size / 2); // divide the array into two almost equal parts\n    mergeSort(ar + size / 2, size - size / 2);\n\n    int index = 0, left = 0, right = size / 2; // merge them\n    int *temp = new int[size];\n\n    while (left < size / 2 or right < size) {\n        if (right == size or (left < size / 2 and ar[left] < ar[right]))\n            temp[index++] = ar[left++];\n        else\n            temp[index++] = ar[right++];\n    }\n    for (int i = 0; i < size; i++)\n        ar[i] = temp[i];\n    delete[] temp;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#quick-sort","title":"Quick Sort","text":"

Quick Sort is also a Divide and Conquer algorithm. The algorithm chooses an element from the array as a pivot and partitions the array around it. Partitioning is arranging the array that satisfies those: the pivot should be put to its correct place, all smaller values should be placed before the pivot, and all greater values should be placed after the pivot. The partitioning can be done in linear time, and after the partitioning, we can use the same sorting function to solve the left part of the pivot and the right part of the pivot recursively.

If the sellected pivot cannot divide the array uniformly after the partitioning, the time complexity can reach \\(\\mathcal{O}(n ^ 2)\\) like insertion sort. To avoid this, the pivot can generally be picked randomly.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_3","title":"Procedure","text":"
  1. If the size of the array is \\(1\\), it is sorted already, stop the algorithm (base case),
  2. Choose a pivot randomly,
  3. For all values in the array, collect smaller values in the left of the array and greater values in the right of array,
  4. Move the pivot to the correct place,
  5. Repeat the same algorithm for the left partition and the right partition.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_3","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(\\tfrac{N}{10}\\right) + T\\left(9 \\cdot \\tfrac{N}{10}\\right) + \\mathcal{O}(N) \\\\ T(N) &= \\mathcal{O}(N \\cdot \\log N) \\end{align*} \\]

void quickSort(int *ar, int size) {\n    if (size <= 1) // base case\n        return;\n\n    int position = 1; // find the correct place of pivot\n    swap(ar[0], ar[rand() % size]);\n\n    for (int i = 1; i < size; i++)\n        if (ar[0] > ar[i])\n            swap(ar[i], ar[position++]);\n    swap(ar[0], ar[position - 1]);\n\n    quickSort(ar, position - 1);\n    quickSort(ar + position, size - position);\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#radix-sort","title":"Radix Sort","text":"

Quick Sort and Merge Sort are comparison-based sorting algorithms and cannot run better than \\(\\mathcal{O}(N \\log N)\\). However, Radix Sort works in linear time (\\(\\mathcal{O}(N + K)\\), where \\(K\\) is \\(\\log(\\max(ar))\\)).

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_4","title":"Procedure","text":"
  1. For each digit from the least significant to the most, sort the array using Counting Sort according to corresponding digit. Counting Sort is used for keys between specific range, and it counts the number of elements which have different key values. After counting the number of distict key values, we can determine the position of elements in the array.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_4","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= \\mathcal{O}(N) \\end{align*} \\]

void radixSort(int *ar, int size, int base = 10) {\n    int *temp = new int[size];\n    int *count = new int[base]();\n\n    // Find the maximum value.\n    int maxx = ar[0];\n    for (int i = 1; i < size; i++) {\n        if (ar[i] > maxx) {\n            maxx = ar[i];\n        }\n    }\n\n    for (int e = 1; maxx / e > 0; e *= base) {\n        memset(count, 0, sizeof(int) * base);\n\n        for (int i = 0; i < size; i++)\n            count[(ar[i] / e) % base]++;\n\n        for (int i = 1; i < base; i++)\n            count[i] += count[i - 1];\n\n        for (int i = size - 1; 0 <= i; i--)\n            temp[--count[(ar[i] / e) % base]] = ar[i];\n\n        for (int i = 0; i < size; i++)\n            ar[i] = temp[i];\n    }\n\n    delete[] temp;\n    delete[] count;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#quickselect-algorithm","title":"Quickselect Algorithm","text":"

Quickselect is a selection algorithm that finds the \\(k^{th}\\) smallest element in an unordered list. The algorithm is closely related to QuickSort in partitioning stage; however, instead of recurring for both sides, it recurs only for the part that contains the \\(k^{th}\\) smallest element.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_5","title":"Procedure","text":"
  1. Choose a pivot randomly,
  2. For all values in the array, collect smaller values in the left of the array and greater values in the right of the array,
  3. Move the pivot to the correct place,
  4. If the current position is equal to \\(k\\), return the value at the position.
  5. If the current position is more than \\(k\\), repeat the same algorithm for the left partition.
  6. Else, update \\(k\\) and repeat the same algorithm for the right partition.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_5","title":"Complexity","text":"
  • In average: \\(\\mathcal{O}(N)\\)
  • Worst-case: \\(\\mathcal{O}(N^2)\\)

Note that this algorithm is fast in practice, but has poor worst-case performance, like quicksort. However, it still performs better on average than other algorithms that find the \\(k^{th}\\) smallest element in \\(\\mathcal{O}(n)\\) in the worst case.

// This function finds the k-th smallest element in arr within size si.\nint QuickSelect(int *arr, int si, int k) {\n    // Check if k is valid and if arr has no less elements than k.\n    if (0 < k && k <= si) {\n        // The quicksort-like partitioning. It is same until we find the index of the pivot.\n        int ind = 0;\n\n        // Get a random pivot to decrease the chance of getting worst-case scenario.\n        swap(arr[si - 1], arr[rand() % si]);\n        for (int j = 0; j < si - 1; j++) {\n            if (arr[j] <= arr[si - 1]) {\n                swap(arr[j], arr[ind]);\n                ind++;\n            }\n        }\n        swap(arr[si - 1], arr[ind]);\n\n        // Now check and recur to appropriate situation.\n        // If the index is equal with k-1 (as our array is 0-indexed) return the value.\n        if (ind == k - 1) {\n            return arr[ind];\n        }\n        // Else check if index is greater than k-1. If it is, recur to the left part.\n        else if (ind > k - 1) {\n            return QuickSelect(arr, ind, k);\n        }\n        // Else, recur to the right part.\n        else {\n            return QuickSelect(arr + ind + 1, si - ind - 1, k - ind - 1);\n        }\n    }\n    // If invalid values is given\n    return INT_MAX;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#divide-and-conquer","title":"Divide and Conquer","text":"

Divide and Conquer is a well-known paradigm that breaks up the problem into several parts, solves each part independently, and finally combines the solutions to the subproblems into the overall solution. Because each subproblem is solved recursively, they should be the smaller versions of the original problem; and the problem must have a base case to end the recursion.

Some example algorithms that use divide and conquer technique:

  • Merge Sort
  • Count Inversions
  • Finding the Closest Pair of Points
  • Others
The Flow of Divide and Conquer","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"data-structures/","title":"Data Structures","text":"

Editor: Tahsin Enes Kuru

Reviewers: Baha Eren Yald\u0131z, Burak Bu\u011frul

Contributors: Kerim Kochekov

","tags":["Data Structures"]},{"location":"data-structures/#giris","title":"Giri\u015f","text":"

Bilgisayar biliminde veri yap\u0131lar\u0131, belirli bir eleman k\u00fcmesi \u00fczerinde verimli bir \u015feklide bilgi edinmemize ayn\u0131 zamanda bu elemanlar \u00fczerinde de\u011fi\u015fiklikler yapabilmemize olanak sa\u011flayan yap\u0131lard\u0131r. \u00c7al\u0131\u015fma prensipleri genellikle elemanlar\u0131n de\u011ferlerini belirli bir kurala g\u00f6re saklamak daha sonra bu yap\u0131lar\u0131 kullanarak elemanlar hakk\u0131nda sorulara (mesela, bir dizinin belirli bir aral\u0131\u011f\u0131ndaki en k\u00fc\u00e7\u00fck say\u0131y\u0131 bulmak gibi) cevap aramakt\u0131r.

","tags":["Data Structures"]},{"location":"data-structures/#dinamik-veri-yaplar","title":"Dinamik Veri Yap\u0131lar\u0131","text":"","tags":["Data Structures"]},{"location":"data-structures/#linked-list","title":"Linked List","text":"","tags":["Data Structures"]},{"location":"data-structures/#stack","title":"Stack","text":"","tags":["Data Structures"]},{"location":"data-structures/#queue","title":"Queue","text":"","tags":["Data Structures"]},{"location":"data-structures/#deque","title":"Deque","text":"","tags":["Data Structures"]},{"location":"data-structures/#fenwick-tree","title":"Fenwick Tree","text":"","tags":["Data Structures"]},{"location":"data-structures/#segment-tree","title":"Segment Tree","text":"","tags":["Data Structures"]},{"location":"data-structures/#trie","title":"Trie","text":"","tags":["Data Structures"]},{"location":"data-structures/#statik-veri-yaplar","title":"Statik Veri Yap\u0131lar\u0131","text":"","tags":["Data Structures"]},{"location":"data-structures/#prefix-sum","title":"Prefix Sum","text":"","tags":["Data Structures"]},{"location":"data-structures/#sparse-table","title":"Sparse Table","text":"","tags":["Data Structures"]},{"location":"data-structures/#sqrt-decomposition","title":"SQRT Decomposition","text":"","tags":["Data Structures"]},{"location":"data-structures/#mos-algorithm","title":"Mo's Algorithm","text":"","tags":["Data Structures"]},{"location":"data-structures/#common-problems","title":"Common Problems","text":"","tags":["Data Structures"]},{"location":"data-structures/#lca","title":"LCA","text":"","tags":["Data Structures"]},{"location":"data-structures/#ornek-problemler","title":"\u00d6rnek Problemler","text":"

Veri yap\u0131lar\u0131 \u00fczerinde pratik yapabilmeniz i\u00e7in \u00f6nerilen problemler:

  1. Link
  2. Link
  3. Link
  4. Link
  5. Link
","tags":["Data Structures"]},{"location":"data-structures/#faydal-baglantlar","title":"Faydal\u0131 Ba\u011flant\u0131lar","text":"
  1. https://en.wikipedia.org/wiki/Data_structure
  2. https://cp-algorithms.com/data_structures/sparse-table.html
  3. https://cp-algorithms.com/data_structures/segment_tree.html
  4. https://cp-algorithms.com/data_structures/fenwick.html
  5. https://cp-algorithms.com/data_structures/sqrt_decomposition.html
  6. https://cses.fi/book/book.pdf
  7. https://visualgo.net/en/segmenttree
  8. https://visualgo.net/en/fenwicktree
  9. https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2
  10. http://www.cs.ukzn.ac.za/~hughm/ds/slides/20-stacks-queues-deques.pdf
  11. https://www.geeksforgeeks.org/stack-data-structure
  12. https://www.geeksforgeeks.org/queue-data-structure
  13. https://www.geeksforgeeks.org/deque-set-1-introduction-applications
  14. https://www.geeksforgeeks.org/linked-list-set-1-introduction
  15. https://www.geeksforgeeks.org/binary-indexed-tree-range-updates-point-queries
  16. https://visualgo.net/en/list
  17. https://cp-algorithms.com/data_structures/fenwick.html
","tags":["Data Structures"]},{"location":"data-structures/deque/","title":"Deque","text":"

Deque veri yap\u0131s\u0131 stack ve queue veri yap\u0131lar\u0131na g\u00f6re daha kapsaml\u0131d\u0131r. Bu veri yap\u0131s\u0131nda yap\u0131n\u0131n en \u00fcst\u00fcne eleman eklenebilirken ayn\u0131 zamanda en alt\u0131na da eklenebilir. Ayn\u0131 \u015fekilde yap\u0131n\u0131n hem en \u00fcst\u00fcndeki eleman\u0131na hem de en alttaki eleman\u0131na eri\u015fim ve silme i\u015flemleri uygulanabilir. Bu veri yap\u0131s\u0131nda uyguluyabildi\u011fimiz i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcne eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131na eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki eleman\u0131na eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131na eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki eleman\u0131 silme.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131 silme.

C++ dilindeki STL k\u00fct\u00fcphanesinde bulunan haz\u0131r deque yap\u0131s\u0131n\u0131n kullan\u0131m\u0131 a\u015fa\u011f\u0131daki gibidir:

int main() {\n    deque<int> q;\n    q.push_front(5);   // deque'nin en altina 5'i ekler.\n    q.push_back(6);    // deque'nin en ustune 6'yi ekler.\n    int x = q.front(); // deque'nin en altindaki elemanina erisim.\n    int y = q.back();  // deque'nin en ustundeki elemanina erisim.\n    q.pop_front();     // deque'nin en altindaki elemanini silme.\n    q.pop_back();      // deque'nin en ustundeki elemanini silme.\n}\n

P.S. deque veri yap\u0131s\u0131 stack ve queue veri yap\u0131lar\u0131na g\u00f6re daha kapsaml\u0131 oldu\u011fundan \u00f6t\u00fcr\u00fc stack ve queue veri yap\u0131lar\u0131na g\u00f6re 2 kat fazla memory kulland\u0131\u011f\u0131n\u0131 a\u00e7\u0131kl\u0131kla s\u00f6yleyebiliriz.

","tags":["Data Structures","Deque"]},{"location":"data-structures/fenwick-tree/","title":"Fenwick Tree","text":"

Binary Indexed Tree olarak da bilinen Fenwick Tree, Prefix Sum ve Sparse Table yap\u0131lar\u0131na benzer bir yap\u0131da olup dizi \u00fczerinde de\u011fi\u015fiklik yapabilmemize olanak sa\u011flayan bir veri yap\u0131s\u0131d\u0131r. Fenwick Tree'nin di\u011fer veri yap\u0131lar\u0131na g\u00f6re en b\u00fcy\u00fck avantaj\u0131 pratikte daha h\u0131zl\u0131 olmas\u0131 ve haf\u0131za karma\u015f\u0131kl\u0131\u011f\u0131n\u0131n \\(\\mathcal{O}(N)\\) olmas\u0131d\u0131r. Ancak Fenwick Tree'de sadece prefix cevaplar\u0131 (veya suffix cevaplar\u0131) saklayabildi\u011fimizden aral\u0131klarda minimum, maksimum ve EBOB gibi baz\u0131 sorgular\u0131n cevaplar\u0131n\u0131 elde edemeyiz.

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#yaps-ve-kurulusu","title":"Yap\u0131s\u0131 ve Kurulu\u015fu","text":"

\\(g(x)\\), \\(x\\) say\u0131s\u0131n\u0131n bit g\u00f6steriminde yaln\u0131zca en sa\u011fdaki bitin 1 oldu\u011fu tam say\u0131 olsun. \u00d6rne\u011fin \\(20\\)'nin bit g\u00f6sterimi \\((10100)_2\\) oldu\u011fundan \\(g(20)=4\\)'t\u00fcr. \u00c7\u00fcnk\u00fc ilk kez sa\u011fdan \\(3.\\) bit \\(1\\)'dir ve \\((00100)_2=4\\)'t\u00fcr. Fenwick Tree'nin \\(x\\) indeksli d\u00fc\u011f\u00fcm\u00fcnde, \\(x - g(x) + 1\\) indeksli elemandan \\(x\\) indeksli elemana kadar olan aral\u0131\u011f\u0131n cevab\u0131n\u0131 saklayacak \u015fekilde kurulur.

$8$ uzunlu\u011fundaki bir dizi i\u00e7in kurulmu\u015f Fenwick Tree yap\u0131s\u0131","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#sorgu-algoritmas","title":"Sorgu Algoritmas\u0131","text":"

Herhangi bir \\([1,x]\\) aral\u0131\u011f\u0131 i\u00e7in sorgu algoritmas\u0131 s\u0131ras\u0131 ile \u015fu \u015feklide \u00e7al\u0131\u015f\u0131r:

  1. Arad\u0131\u011f\u0131m\u0131z cevaba \\([x - g(x) + 1,x]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 ekle.
  2. \\(x\\)'in de\u011ferini \\(x - g(x)\\) yap. E\u011fer \\(x\\)'in yeni de\u011feri \\(0\\)'dan b\u00fcy\u00fck ise \\(1.\\) i\u015flemden hesaplamaya devam et.

\\([1,x]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 hesaplamak i\u00e7in yap\u0131lan i\u015flem say\u0131s\u0131 \\(x\\) say\u0131s\u0131n\u0131n \\(2\\)'lik tabandaki yaz\u0131l\u0131\u015f\u0131ndaki \\(1\\) say\u0131s\u0131na e\u015fittir. \u00c7\u00fcnk\u00fc her d\u00f6ng\u00fcde \\(x\\)'ten \\(2\\)'lik tabandaki yaz\u0131l\u0131\u015f\u0131ndaki en sa\u011fdaki \\(1\\) bitini \u00e7\u0131kart\u0131yoruz. Dolay\u0131s\u0131yla sorgu i\u015flemimiz \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r. \\([l,r]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 da \\([1,r]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131ndan \\([1,l - 1]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 \u00e7\u0131kararak kolay bir \u015fekilde elde edebiliriz.

NOT: \\(g(x)\\) de\u011ferini bitwise operat\u00f6rlerini kullanarak a\u015fa\u011f\u0131daki e\u015fitlikle kolay bir \u015fekilde hesaplayabiliriz: \\[g(x) = x \\ \\& \\ (-x)\\]

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#eleman-guncelleme-algoritmas","title":"Eleman G\u00fcncelleme Algoritmas\u0131","text":"

Dizideki \\(x\\) indeksli eleman\u0131n\u0131n de\u011ferini g\u00fcncellemek i\u00e7in kullan\u0131lan algoritma \u015fu \u015feklide \u00e7al\u0131\u015f\u0131r:

  • A\u011fa\u00e7ta \\(x\\) indeksli eleman\u0131 i\u00e7eren t\u00fcm d\u00fc\u011f\u00fcmlerin de\u011ferlerini g\u00fcncelle.

Fenwick Tree'de \\(x\\) indeksli eleman\u0131 i\u00e7eren maksimum \\(\\log(N)\\) tane aral\u0131k oldu\u011fundan g\u00fcncelleme algoritmas\u0131 \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r.

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#ornek-kod-parcalar","title":"\u00d6rnek Kod Par\u00e7alar\u0131","text":"
const int n;\nint tree[n + 1], a[n + 1];\n\nvoid add(int val, int x) { // x indeksli elemanin degerini val degeri kadar artirir.\n    // x indeksinin etkiledigi butun dugumleri val degeri kadar artirir.\n    while (x <= n) {\n        tree[x] += val;\n        x += x & (-x);\n    }\n}\n\nint sum(int x) { // 1 indeksli elemandan x indeksli elemana\n    int res = 0; // kadar olan sayilarin toplamini verir.\n    while (x >= 1) {\n        res += tree[x];\n        x -= x & (-x);\n    }\n    return res;\n}\n\nint query(int l, int r) { // [l,r] araligindaki elemanlarin toplamini verir.\n    return sum(r) - sum(l - 1);\n}\n\nvoid build() { // a dizisi uzerine fenwick tree yapisini kuruyoruz.\n    for (int i = 1; i <= n; i++)\n        add(a[i], i);\n}\n

Fenwick Tree veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#aralk-guncelleme-ve-eleman-sorgu","title":"Aral\u0131k G\u00fcncelleme ve Eleman Sorgu","text":"

Bir \\(a\\) dizisi \u00fczerinde i\u015flemler yapaca\u011f\u0131m\u0131z\u0131 varsayal\u0131m daha sonra \\(a\\) dizisi \\(b\\) dizisinin prefix sum dizisi olacak \u015fekilde bir \\(b\\) dizisi tan\u0131mlayal\u0131m. Ba\u015fka bir deyi\u015fle $a_i = \\displaystyle\\sum_{j=1}^{i} {b_j} $ olmal\u0131d\u0131r. Sonradan olu\u015fturdu\u011fumuz \\(b\\) dizisi \u00fczerine Fenwick Tree yap\u0131s\u0131n\u0131 kural\u0131m. \\([l,r]\\) aral\u0131\u011f\u0131ndaki her elemana \\(x\\) de\u011ferini eklememiz i\u00e7in uygulamam\u0131z gereken i\u015flemler:

  • \\(b_l\\) de\u011ferini \\(x\\) kadar art\u0131r. B\u00f6ylelikle \\(l\\) indeksli elemandan dizinin sonuna kadar t\u00fcm elemanlar\u0131n de\u011feri \\(x\\) kadar artm\u0131\u015f olur.
  • \\(b_{r + 1}\\) de\u011ferini \\(x\\) kadar azalt. B\u00f6ylelikle \\(r + 1\\) indeksli elemandan dizinin sonuna kadar t\u00fcm elemanlar\u0131n de\u011feri \\(x\\) kadar azalm\u0131\u015f olur. Bu i\u015flemelerin sonucunda sadece \\([l,r]\\) aral\u0131\u011f\u0131ndaki elemanlar\u0131n de\u011feri \\(x\\) kadar artm\u0131\u015f olur.
","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#ornek-kod-parcalar_1","title":"\u00d6rnek Kod Par\u00e7alar\u0131","text":"
const int n;\nint a[n + 1], b[n + 1];\n\nvoid add(int val, int x) { // x indeksli elemanin degerini val degeri kadar artirir.\n    while (x <= n) {\n        tree[x] += val;\n        x += x & (-x);\n    }\n}\n\nint sum(int x) { // 1 indeksli elemandan x indeksli elemana\n    int res = 0; // kadar olan sayilarin toplamini verir.\n    while (x >= 1) {\n        res += tree[x];\n        x -= x & (-x);\n    }\n    return res;\n}\nvoid build() {\n    for (int i = 1; i <= n; i++)\n        b[i] = a[i] - a[i - 1]; // b dizisini olusturuyoruz.\n\n    for (int i = 1; i <= n; i++)\n        add(b[i], i); // b dizisi uzerine fenwick tree kuruyoruz.\n}\n\nvoid update(int l, int r, int x) {\n    add(x, l);\n    add(-x, r + 1);\n}\n\nvoid query(int x) { return sum(x); }\n
","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/linked-list/","title":"Linked List","text":"

Linked List veri yap\u0131s\u0131nda elemanlar, her eleman kendi de\u011ferini ve bir sonraki eleman\u0131n adresini tutacak \u015fekilde saklan\u0131r. Yap\u0131daki elemanlar ba\u015f elemandan (head) ba\u015flanarak son elemana (tail) gidecek \u015fekilde gezilebilir. Diziye kar\u015f\u0131n avantaj\u0131 haf\u0131zan\u0131n dinamik bir \u015fekilde kullan\u0131lmas\u0131d\u0131r. Bu veri yap\u0131s\u0131nda uygulanabilecek i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n sonuna eleman ekleme.
  • Anl\u0131k veri yap\u0131s\u0131n\u0131 ba\u015ftan (head) sona (tail) gezme.
\u00d6rnek bir Linked List yap\u0131s\u0131
// Her bir elemani (burada sayilari, yani int) tutacak struct olusturuyoruz.\nstruct node {\n    int data;\n    node *next;\n};\nnode *head, *tail;\n\nvoid push_back(int x) {\n    // Yeni elemanimizi hafizada olusturuyoruz.\n    node *t = (node *)malloc(sizeof(node));\n    t->data = x;    // Elemanin verisini atiyoruz.\n    t->next = NULL; // Sona ekledigimizden sonraki elemanina NULL atiyoruz.\n\n    // Eger veri yapimiza hic eleman eklenmediyse head\n    // ve tail elemanlarini olusturuyoruz.\n    if (head == NULL && tail == NULL) {\n        head = t;\n        tail = t;\n    }\n    // Eklenmisse yeni tail elemanimizi guncelliyoruz.\n    else {\n        tail->next = t;\n        tail = t;\n    }\n}\n\nvoid print() {\n    // Dizideki tum elemanlari geziyoruz.\n    node *t = head;\n    while (t != NULL) {\n        printf(\"%d \", t->data);\n        t = t->next;\n    }\n}\n
","tags":["Data Structures","Linked List"]},{"location":"data-structures/lowest-common-ancestor/","title":"Lowest Common Ancestors","text":"

This problem consists of queries, LCA(x, y), and asks for the ancestor of both x and y whose depth is maximum. We will use a similar algorithm to the jump pointer algorithm with implementation.

","tags":["Tree","LCA","Lowest Common Ancestors","Binary Lifting"]},{"location":"data-structures/lowest-common-ancestor/#initialization","title":"Initialization","text":"

As we did in Jump Pointer Method, we will calculate node's all \\(2^i\\). ancestors if they exist. L[x][y] corresponds to x's \\(2^y\\). ancestors. Hence L[x][0] is basically the parent of x.

void init() {\n    for(int x=1 ; x<=n ; x++)\n        L[x][0] = parent[x];\n\n    for(int y=1 ; y<=logN ; y++)\n        for(int x=1 ; x<=n ; x++)\n            L[x][y] = L[L[x][y-1]][y-1];\n}\n
Note that we have used the fact that x's \\(2^y\\). ancestor is x's \\(2^{y\u22121}\\). ancestor's \\(2^{y\u22121}\\). ancestor.

","tags":["Tree","LCA","Lowest Common Ancestors","Binary Lifting"]},{"location":"data-structures/lowest-common-ancestor/#queries-binary-lifting","title":"Queries-Binary Lifting","text":"

Given LCA(x, y), we calculate answer by following:

Firstly, ensure that both x and y are in same depth. If it is not take the deepest one to the other one's depth. Then control whether x and y is equal. If they are equal, that means the lowest common ancestor is x. After that, from i = log(N), check that if x's \\(2^i\\). ancestor is equal to y's \\(2^i\\). ancestor. If they are not equal that means LCA is somewhere above the \\(2^i\\). ancestors of x and y. Then we continue to search LCA of y and x\u2019s ancestors as LCA(L[x][i], L[y][i]) is the same as LCA(x, y). Please notice that we have ensured that depth di\ufb00erence between LCA and both x and y are no longer larger than \\(2^i\\). If we apply this producure until i = 0, we would left with x and y such that parent of x is LCA. Of course, the parent of y would also be LCA.

","tags":["Tree","LCA","Lowest Common Ancestors","Binary Lifting"]},{"location":"data-structures/mo-algorithm/","title":"Mo's Algorithm","text":"

This method will be a key for solving offline range queries on an array. By offline, we mean we can find the answers of these queries in any order we want and there are no updates. Let\u2019s introduce a problem and construct an efficient solution for it.

You have an array a with \\(N\\) elements such that it\u2019s elements ranges from \\(1\\) to \\(M\\). You have to answer \\(Q\\) queries. Each is in the same type. You will be given a range \\([l, r]\\) for each query, you have to print how many different values are there in the subarray \\([a_l , a_{l+1}..a_{r\u22121}, a_r]\\).

First let\u2019s find a naive solution and improve it. Remember the frequency array we mentioned before. We will keep a frequency array that contains only given subarray\u2019s values. Number of values in this frequency array bigger than 0 will be our answer for given query. Then we have to update frequency array for next query. We will use \\(\\mathcal{O}(N)\\) time for each query, so total complexity will be \\(\\mathcal{O}(Q \\times N)\\). Look at the code below for implementation.

class Query {\n   public:\n    int l, r, ind;\n    Query(int l, int r, int ind) {\n        this->l = l, this->r = r, this->ind = ind;\n    }\n};\n\nvoid del(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 1) num--;\n    F[a[ind]]--;\n}\n\nvoid add(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 0) num++;\n    F[a[ind]]++;\n}\n\nvector<int> solve(vector<int> &a, vector<Query> &q) {\n    int Q = q.size(), N = a.size();\n    int M = *max_element(a.begin(), a.end());\n    vector<int> F(M + 1, 0);  // This is frequency array we mentioned before\n    vector<int> ans(Q, 0);\n    int l = 0, r = -1, num = 0;\n    for (int i = 0; i < Q; i++) {\n        int nl = q[i].l, nr = q[i].r;\n        while (l < nl) del(l++, a, F, num);\n        while (l > nl) add(--l, a, F, num);\n        while (r > nr) del(r--, a, F, num);\n        while (r < nr) add(++r, a, F, num);\n        ans[q[i].ind] = num;\n    }\n    return ans;\n}\n

Time complexity for each query here is \\(\\mathcal{O}(N)\\). So total complexity is \\(\\mathcal{O}(Q \\times N)\\). Just by changing the order of queries we will reduce this complexity to \\(\\mathcal{O}((Q + N) \\times \\sqrt N)\\).

","tags":["Data Structures","Mo's Algorithm"]},{"location":"data-structures/mo-algorithm/#mos-algorithm","title":"Mo's Algorithm","text":"

We will change the order of answering the queries such that overall complexity will be reduced drastically. We will use following cmp function to sort our queries and will answer them in this sorted order. Block size here is \\(\\mathcal{O}(\\sqrt N)\\).

bool operator<(Query other) const {\n    return make_pair(l / block_size, r) <\n        make_pair(other.l / block_size, other.r);\n}\n

Why does that work? Let\u2019s examine what we do here first then find the complexity. We divide \\(l\\)'s of queries into blocks. Block number of a given \\(l\\) is \\(l\\) blocksize (integer division). We sort the queries first by their block numbers then for same block numbers, we sort them by their \\(r\\)'s. Sorting all queries will take \\(\\mathcal{O}(Q \\times log{Q})\\) time. Let\u2019s look at how many times we will call add and del operations to change current \\(r\\). For the same block \\(r\\)'s always increases. So for same block it is \\(\\mathcal{O}(N)\\) since it can only increase. Since there are \\(N\\) blocksize blocks in total, it will be \\(\\mathcal{O}(N \\times N / \\text{block\\_size})\\) operations in total. For same block, add and del operations that changes \\(l\\) will be called at most \\(\\mathcal{O}(\\text{block\\_size})\\) times for each query, since if block number is same then their \\(l\\)'s must differ at most by \\(\\mathcal{O}(\\text{block\\_size})\\). So overall it is \\(\\mathcal{O}(Q \\times \\text{block\\_size})\\). Also when consecutive queries has different block numbers we will perform at most \\(\\mathcal{O}(N)\\) operations, but notice that there are at most \\(\\mathcal{O}(N \\div \\text{block\\_size})\\) such consecutive queries, so it doesn't change the overall time complexity. If we pick \\(block\\_size = \\sqrt N\\) overall complexity will be \\(\\mathcal{O}((Q + N) \\times \\sqrt N)\\). Full code is given below.

Example for the Algorithm
int block_size;\n\nclass Query {\n   public:\n    int l, r, ind;\n    Query(int l, int r, int ind) {\n        this->l = l, this->r = r, this->ind = ind;\n    }\n    bool operator<(Query other) const {\n        return make_pair(l / block_size, r) <\n               make_pair(other.l / block_size, other.r);\n    }\n};\n\nvoid del(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 1) num--;\n    F[a[ind]]--;\n}\n\nvoid add(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 0) num++;\n    F[a[ind]]++;\n}\n\nvector<int> solve(vector<int> &a, vector<Query> &q) {\n    int Q = q.size(), N = a.size();\n    int M = *max_element(a.begin(), a.end());\n    block_size = sqrt(N);\n    sort(q.begin(), q.end());\n    vector<int> F(M + 1, 0);  // This is frequency array we mentioned before\n    vector<int> ans(Q, 0);\n    int l = 0, r = -1, num = 0;\n    for (int i = 0; i < Q; i++) {\n        int nl = q[i].l, nr = q[i].r;\n        while (l < nl) del(l++, a, F, num);\n        while (l > nl) add(--l, a, F, num);\n        while (r > nr) del(r--, a, F, num);\n        while (r < nr) add(++r, a, F, num);\n        ans[q[i].ind] = num;\n    }\n    return ans;\n}\n
","tags":["Data Structures","Mo's Algorithm"]},{"location":"data-structures/prefix-sum/","title":"Prefix Sum","text":"

Prefix Sum dizisi bir dizinin prefixlerinin toplamlar\u0131yla olu\u015fturulan bir veri yap\u0131s\u0131d\u0131r. Prefix sum dizisinin \\(i\\) indeksli eleman\u0131 girdi dizisindeki \\(1\\) indeksli elemandan \\(i\\) indeksli elemana kadar olan elemanlar\u0131n toplam\u0131na e\u015fit olacak \u015fekilde kurulur. Ba\u015fka bir deyi\u015fle:

\\[sum_i = \\sum_{j=1}^{i} {a_j}\\]

\u00d6rnek bir \\(A\\) dizisi i\u00e7in prefix sum dizisi \u015fu \u015fekilde kurulmal\u0131d\u0131r:

A Dizisi \\(4\\) \\(6\\) \\(3\\) \\(12\\) \\(1\\) Prefix Sum Dizisi \\(4\\) \\(10\\) \\(13\\) \\(25\\) \\(26\\) \\(4\\) \\(4+6\\) \\(4+6+3\\) \\(4+6+3+12\\) \\(4+6+3+12+1\\)

Prefix sum dizisini kullanarak herhangi bir \\([l,r]\\) aral\u0131\u011f\u0131ndaki elemanlar\u0131n toplam\u0131n\u0131 \u015fu \u015fekilde kolayl\u0131kla elde edebiliriz:

\\[sum_r = \\sum_{j=1}^{r} {a_j}\\]

\\[sum_{l - 1} = \\sum_{j=1}^{l - 1} {a_j}\\]

\\[sum_r - sum_{l-1} = \\sum_{j=l}^{r} {a_j}\\]

","tags":["Data Structures","Prefix Sum"]},{"location":"data-structures/prefix-sum/#ornek-kod-parcalar","title":"\u00d6rnek Kod Par\u00e7alar\u0131","text":"

Prefix Sum dizisini kurarken \\(sum_i = sum_{i - 1} + a_i\\) e\u015fitli\u011fi kolayca g\u00f6r\u00fclebilir ve bu e\u015fitli\u011fi kullanarak \\(sum[]\\) dizisini girdi dizisindeki elemanlar\u0131 s\u0131rayla gezerek kurabiliriz:

const int n;\nint sum[n + 1], a[n + 1];\n// a dizisi girdi dizimiz, sum dizisi de prefix sum dizimiz olsun.\n\nvoid build() {\n    for (int i = 1; i <= n; i++)\n        sum[i] = sum[i - 1] + a[i];\n    return;\n}\n\nint query(int l, int r) {\n    return sum[r] - sum[l - 1];\n}\n
","tags":["Data Structures","Prefix Sum"]},{"location":"data-structures/prefix-sum/#zaman-karmasklg","title":"Zaman Karma\u015f\u0131kl\u0131\u011f\u0131","text":"

Prefix sum dizisini kurma i\u015flemimizin zaman ve haf\u0131za karma\u015f\u0131kl\u0131\u011f\u0131 \\(\\mathcal{O}(N)\\). Her sorguya da \\(\\mathcal{O}(1)\\) karma\u015f\u0131kl\u0131kta cevap verebiliyoruz.

Prefix sum veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","Prefix Sum"]},{"location":"data-structures/queue/","title":"Queue","text":"

Queue veri yap\u0131s\u0131nda elemanlar yap\u0131ya ilk giren ilk \u00e7\u0131kar (FIFO) kural\u0131na uygun olacak \u015fekilde saklan\u0131r. Bu veri yap\u0131s\u0131nda uygulayabildigimiz i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcne eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131na eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131 silme.
  • Veri yap\u0131s\u0131n\u0131n bo\u015f olup olmad\u0131\u011f\u0131n\u0131n kontr\u00f6l\u00fc.

C++ dilindeki STL k\u00fct\u00fcphanesinde bulunan haz\u0131r queue yap\u0131s\u0131n\u0131n kullan\u0131m\u0131 a\u015fa\u011f\u0131daki gibidir:

int main() {\n    queue<int> q;\n    cout << q.empty() << endl; // Ilk bashta Queue bosh oldugu icin burada True donecektir.\n    q.push(5);                 // Queue'in en ustune 5'i ekler. Queue'in yeni hali: {5}\n    q.push(7);                 // Queue'in en ustune 7'yi ekler. Queue'in yeni hali: {7, 5}\n    q.push(6);                 // Queue'in en ustune 6'yi ekler. Queue'in yeni hali : {6, 7, 5}\n    q.pop();                   // Queue'in en altindaki elemani siler. Queue'in yeni hali : {6, 7}\n    q.push(1);                 // Queue'in en ustune 1'i ekler. Queue'in yeni hali : {1, 6, 7}\n    cout << Q.front() << endl; // Queue'in en ustundeki elemana erisir. Ekrana 7 yazdirir.\n}\n
","tags":["Data Structures","Queue"]},{"location":"data-structures/segment-tree/","title":"Segment Tree","text":"

Segment Tree is a data structure that enables us to answer queries like minimum, maximum, sum etc. for any \\([l,r]\\) interval in \\(\\mathcal{O}(\\log N)\\) time complexity and update these intervals.

Segment Tree is more useful than Fenwick Tree and Sparse Table structures because it allows updates on elements and provides the possibility to answer queries like minimum, maximum etc. for any \\([l,r]\\) interval. Also, the memory complexity of Segment Tree is \\(\\mathcal{O}(N)\\) while the memory complexity of the Sparse Table structure is \\(\\mathcal{O}(N \\log N)\\).

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#structure-and-construction","title":"Structure and Construction","text":"

Segment Tree has a \"Complete Binary Tree\" structure. The leaf nodes of the Segment Tree store the elements of the array, and each internal node's value is calculated with a function that takes its children's values as inputs. Thus, the answers of certain intervals are stored in each node, and the answer of the whole array is stored in the root node. For example, for a Segment Tree structure built for the sum query, the value of each node is equal to the sum of its children's values.

segment tree structure to query sum on array $a = [41,67,6,30,85,43,39]$
void build(int ind, int l, int r) {\n    // tree[ind] stores the answer of the interval [l,r]\n    if (l == r) {         // leaf node reached\n        tree[ind] = a[l]; // store the value of the leaf node\n    } else {\n        int mid = (l + r) / 2;\n        build(ind * 2, l, mid);\n        build(ind * 2 + 1, mid + 1, r);\n        // the answer of the interval [l,mid] and [mid + 1,r] is the sum of their answers\n        tree[ind] = tree[ind * 2] + tree[ind * 2 + 1];\n    }\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#query-and-update-algorithms","title":"Query and Update Algorithms","text":"","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#query-algorithm","title":"Query Algorithm","text":"

For any \\([l,r]\\) interval, the query algorithm works as follows: - Divide the \\([l,r]\\) interval into the widest intervals that are stored in the tree. - Merge the answers of these intervals to calculate the desired answer.

There are at most \\(2\\) intervals that are needed to calculate the answer at each depth of the tree. Therefore, the query algorithm works in \\(\\mathcal{O}(\\log N)\\) time complexity.

on array $a = [41,67,6,30,85,43,39]$ query at $[2,6]$ interval

On array \\(a = [41,67,6,30,85,43,39]\\), the answer of the \\([2,6]\\) interval is obtained by merging the answers of the \\([2,3]\\) and \\([4,6]\\) intervals. The answer for the sum query is calculated as \\(36+167=203\\).

// [lw,rw] is the interval we are looking for the answer\n// [l,r] is the interval that the current node stores the answer\nint query(int ind, int l, int r, int lw, int rw) {\n    if (l > rw or r < lw) //current interval does not contain the interval we are looking for\n        return 0;\n    if (l >= lw and r <= rw) //current interval is completely inside the interval we are looking for\n        return tree[ind];\n\n    int mid = (l + r) / 2;\n\n    // recursively calculate the answers of all intervals containing the x index\n    return query(ind * 2, l, mid, lw, rw) + query(ind * 2 + 1, mid + 1, r, lw, rw);\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#update-algorithm","title":"Update Algorithm","text":"

Update the value of every node that contains \\(x\\) indexed element.

It is sufficient to update the values of at most \\(\\log(N)\\) nodes from the leaf node containing the \\(x\\) indexed element to the root node. Therefore, the time complexity of updating the value of any element is \\(\\mathcal{O}(\\log N)\\).

the nodes that should be updated when updating the $5^{th}$ index of the array $a = [41,67,6,30,85,43,39]$ are as follows:
void update(int ind, int l, int r, int x, int val) {\n    if (l > x || r < x) // x index is not in the current interval\n        return;\n    if (l == x and r == x) {\n        tree[ind] = val; // update the value of the leaf node\n        return;\n    }\n\n    int mid = (l + r) / 2;\n\n    // recursively update the values of all nodes containing the x index\n    update(ind * 2, l, mid, x, val);\n    update(ind * 2 + 1, mid + 1, r, x, val);\n    tree[ind] = tree[ind * 2] + tree[ind * 2 + 1];\n}\n

A sample problem related to the Segment Tree data structure can be found here.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#segment-tree-with-lazy-propagation","title":"Segment Tree with Lazy Propagation","text":"

Previously, update function was called to update only a single value in array. Please note that a single value update in array may cause changes in multiple nodes in Segment Tree as there may be many segment tree nodes that have this changed single element in it\u2019s range.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#lazy-propogation-algorithm","title":"Lazy Propogation Algorithm","text":"

We need a structure that can perform following operations on an array \\([1,N]\\).

  • Add inc to all elements in the given range \\([l, r]\\).
  • Return the sum of all elements in the given range \\([l, r]\\).

Notice that if update was for single element, we could use the segment tree we have learned before. Trivial structure comes to mind is to use an array and do the operations by traversing and increasing the elements one by one. Both operations would take \\(\\mathcal{O}(L)\\) time complexity in this structure where \\(L\\) is the number of elements in the given range.

Let\u2019s use segment tree\u2019s we have learned. Second operation is easy, We can do it in \\(\\mathcal{O}(\\log N)\\). What about the first operation. Since we can do only single element update in the regular segment tree, we have to update all elements in the given range one by one. Thus we have to perform update operation \\(L\\) times. This works in \\(\\mathcal{O}(L \\times \\log N)\\) for each range update. This looks bad, even worse than just using an array in a lot of cases.

So we need a better structure. People developed a trick called lazy propagation to perform range updates on a structure that can perform single update (This trick can be used in segment trees, treaps, k-d trees ...).

Trick is to be lazy i.e, do work only when needed. Do the updates only when you have to. Using Lazy Propagation we can do range updates in \\(\\mathcal{O}(\\log N)\\) on standart segment tree. This is definitely fast enough.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#updates-using-lazy-propogation","title":"Updates Using Lazy Propogation","text":"

Let\u2019s be lazy as told, when we need to update an interval, we will update a node and mark its children that it needs to be updated and update them when needed. For this we need an array \\(lazy[]\\) of the same size as that of segment tree. Initially all the elements of the \\(lazy[]\\) array will be \\(0\\) representing that there is no pending update. If there is non-zero element \\(lazy[k]\\) then this element needs to update node k in the segment tree before making any query operation, then \\(lazy[2\\cdot k]\\) and \\(lazy[2 \\cdot k + 1]\\) must be also updated correspondingly.

To update an interval we will keep 3 things in mind.

  • If current segment tree node has any pending update, then first add that pending update to current node and push the update to it\u2019s children.
  • If the interval represented by current node lies completely in the interval to update, then update the current node and update the \\(lazy[]\\) array for children nodes.
  • If the interval represented by current node overlaps with the interval to update, then update the nodes as the earlier update function.
void update(int node, int start, int end, int l, int r, int val) {\n    // If there's a pending update on the current node, apply it\n    if (lazy[node] != 0) {\n        tree[node] += (end - start + 1) * lazy[node]; // Apply the pending update\n        // If not a leaf node, propagate the lazy update to the children\n        if (start != end) {\n            lazy[2 * node] += lazy[node];\n            lazy[2 * node + 1] += lazy[node];\n        }\n        lazy[node] = 0; // Clear the pending update\n    }\n\n    // If the current interval [start, end] does not intersect with [l, r], return\n    if (start > r || end < l) {\n        return;\n    }\n\n    // If the current interval [start, end] is completely within [l, r], apply the update\n    if (l <= start && end <= r) {\n        tree[node] += (end - start + 1) * val; // Update the segment\n        // If not a leaf node, propagate the update to the children\n        if (start != end) {\n            lazy[2 * node] += val;\n            lazy[2 * node + 1] += val;\n        }\n        return;\n    }\n\n    // Otherwise, split the interval and update both halves\n    int mid = (start + end) / 2;\n    update(2 * node, start, mid, l, r, val);\n    update(2 * node + 1, mid + 1, end, l, r, val);\n\n    // After updating the children, recalculate the current node's value\n    tree[node] = tree[2 * node] + tree[2 * node + 1];\n}\n

This is the update function for given problem. Notice that when we arrive a node, all the updates that we postponed that would effect this node will be performed since we are pushing them downwards as we go to this node. Thus this node will keep the exact values when the range updates are done without lazy. So it\u2019s seems like it is working. How about queries?

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#queries-using-lazy-propogation","title":"Queries Using Lazy Propogation","text":"

Since we have changed the update function to postpone the update operation, we will have to change the query function as well. The only change we need to make is to check if there is any pending update operation on that node. If there is a pending update, first update the node and then proceed the same way as the earlier query function. As mentioned in the previous subsection, all the postponed updates that would affect this node will be performed before we reach it. Therefore, the sum value we look for will be correct.

int query(int node, int start, int end, int l, int r) {\n    // If the current interval [start, end] does not intersect with [l, r], return 0\n    if (start > r || end < l) {\n        return 0;\n    }\n\n    // If there's a pending update on the current node, apply it\n    if (lazy[node] != 0) {\n        tree[node] += (end - start + 1) * lazy[node]; // Apply the pending update\n        // If not a leaf node, propagate the lazy update to the children\n        if (start != end) {\n            lazy[2 * node] += lazy[node];\n            lazy[2 * node + 1] += lazy[node];\n        }\n        lazy[node] = 0; // Clear the pending update\n    }\n\n    // If the current interval [start, end] is completely within [l, r], return the value\n    if (l <= start && end <= r) {\n        return tree[node];\n    }\n\n    // Otherwise, split the interval and query both halves\n    int mid = (start + end) / 2;\n    int p1 = query(2 * node, start, mid, l, r);       // Query the left child\n    int p2 = query(2 * node + 1, mid + 1, end, l, r); // Query the right child\n\n    // Combine the results from the left and right child nodes\n    return (p1 + p2);\n}\n
Notice that the only difference with the regular query function is pushing the lazy values downwards as we traverse. This is a widely used trick applicable to various problems, though not all range problems. You may notice that we leveraged properties of addition here. The associative property of addition allows merging multiple updates in the lazy array without considering their order. This assumption is crucial for lazy propagation. Other necessary properties are left as an exercise to the reader.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#binary-search-on-segment-tree","title":"Binary Search on Segment Tree","text":"

Assume we have an array A that contains elements between 1 and \\(M\\). We have to perform 2 kinds of operations.

  • Change the value of the element in given index i by x.
  • Return the value of the kth element on the array when sorted.
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#how-to-solve-it-naively","title":"How to Solve It Naively","text":"

Let\u2019s construct a frequency array, \\(F[i]\\) will keep how many times number i occurs in our original array. So we want to find smallest \\(i\\) such that \\(\\sum_{j=1}^{i} F[i] \\geq k\\). Then the number \\(i\\) will be our answer for the query. And for updates we just have to change \\(F\\) array accordingly.

A naive update example

This is the naive algorithm. Update is O(1) and query is O(M).

void update(int i, int x) {\n    F[A[i]]--;\n    F[A[i] = x]++;\n}\n\nint query(int k) {\n    int sum = 0, ans = 0;\n    // Iterate through the frequency array F to find the smallest value\n    // for which the cumulative frequency is at least k\n    for (int i = 1; i <= M; i++) {\n        sum += F[i]; // Add the frequency of F[i] to the cumulative sum\n        if (sum >= k) {\n            return i;\n        }\n    }\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#how-to-solve-it-with-segment-tree","title":"How to Solve It With Segment Tree","text":"

This is of course, slow. Let\u2019s use segment tree\u2019s to improve it. First we will construct a segment tree on \\(F\\) array. Segment tree will perform single element updates and range sum queries. We will use binary search to find corresponding \\(i\\) for \\(k^{th}\\) element queries.

Segment Tree After First Update
void update(int i, int x) {\n    update(1, 1, M, A[i], --F[A[i]]); // Decrement frequency of old value\n    A[i] = x;                        // Update A[i] to new value\n    update(1, 1, M, A[i], ++F[A[i]]); // Increment frequency of new value\n}\n\nint query(int k) {\n    int l = 1, r = m; // Initialize binary search range\n    while (l < r) {\n        int mid = (l + r) / 2; \n        if (query(1, 1, M, 1, mid) < k)\n            l = mid + 1; // Move lower bound up\n        else\n            r = mid; // Move upper bound down\n    }\n    return l; // Return index where cumulative frequency is at least k\n}\n

If you look at the code above you can notice that each update takes \\(\\mathcal{O}(\\log M)\\) time and each query takes \\(\\mathcal{O}(\\log^{2} M)\\) time, but we can do better.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#how-to-speed-up","title":"How To Speed Up?","text":"

If you look at the segment tree solution on preceding subsection you can see that queries are performed in \\(\\mathcal{O}(\\log^{2} M)\\) time. We can make is faster, actually we can reduce the time complexity to \\(\\mathcal{O}(\\log M)\\) which is same with the time complexity for updates. We will do the binary search when we are traversing the segment tree. We first will start from the root and look at its left child\u2019s sum value, if this value is greater than k, this means our answer is somewhere in the left child\u2019s subtree. Otherwise it is somewhere in the right child\u2019s subtree. We will follow a path using this rule until we reach a leaf, then this will be our answer. Since we just traversed \\(\\mathcal{O}(\\log M)\\) nodes (one node at each level), time complexity will be \\(\\mathcal{O}(\\log M)\\). Look at the code below for better understanding.

Solution of First Query
void update(int i, int x) {\n    update(1, 1, M, A[i], --F[A[i]]); // Decrement frequency of old value\n    A[i] = x;                         // Update A[i] to new value\n    update(1, 1, M, A[i], ++F[A[i]]); // Increment frequency of new value\n}\n\nint query(int node, int start, int end, int k) {\n    if (start == end) return start; // Leaf node, return the index\n    int mid = (start + end) / 2; \n    if (tree[2 * node] >= k)\n        return query(2 * node, start, mid, k); // Search in left child\n    return query(2 * node + 1, mid + 1, end, k - tree[2 * node]); // Search in right child\n}\n\nint query(int k) {\n    return query(1, 1, M, k); // Public interface for querying\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/sparse-table/","title":"Sparse Table","text":"

Sparse table aral\u0131klardaki elemanlar\u0131n toplam\u0131, minimumu, maksimumu ve EBOB'lar\u0131 gibi sorgulara \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda cevap alabilmemizi sa\u011flayan bir veri yap\u0131s\u0131d\u0131r. Baz\u0131 tip sorgular (aral\u0131ktaki minimum, maksimum say\u0131y\u0131 bulma gibi) ise \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda yapmaya uygundur.

Bu veri yap\u0131s\u0131 durumu de\u011fi\u015fmeyen, sabit bir veri \u00fczerinde \u00f6n i\u015flemler yaparak kurulur. Dinamik veriler i\u00e7in kullan\u0131\u015fl\u0131 de\u011fildir. Veri \u00fczerinde herhangi bir de\u011fi\u015fiklik durumda Sparse table tekrardan kurulmal\u0131d\u0131r. Bu da maliyetli bir durumdur.

","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sparse-table/#yaps-ve-kurulusu","title":"Yap\u0131s\u0131 ve Kurulu\u015fu","text":"

Sparse table iki bouyutlu bir dizi \u015feklinde, \\(\\mathcal{O}(N\\log N)\\) haf\u0131za karma\u015f\u0131kl\u0131\u011f\u0131na sahip bir veri yap\u0131s\u0131d\u0131r. Dizinin her eleman\u0131ndan \\(2\\)'nin kuvvetleri uzakl\u0131ktaki elemanlara kadar olan cevaplar Sparse table'da saklan\u0131r. \\(ST_{x,i}\\), \\(x\\) indeksli elemandan \\(x + 2^i - 1\\) indeksli elemana kadar olan aral\u0131\u011f\u0131n cevab\u0131n\u0131 saklayacak \u015fekilde sparse table kurulur.

// Toplam sorgusu icin kurulmus Sparse Table Yapisi\nconst int n;\nconst int LOG = log2(n);\nint a[n + 1], ST[2 * n][LOG + 1];\n\nvoid build() {\n    for (int i = 1; i <= n; i++) {\n        // [i,i] araliginin cevabi dizinin i indeksli elemanina esittir.\n        ST[i][0] = a[i];\n    }\n\n    for (int i = 1; i <= LOG; i++)\n        for (int j = 1; j <= n; j++) {\n            // [i,i+2^(j)-1] araliginin cevabi\n            // [i,i+2^(j - 1) - 1] araligi ile [i+2^(j - 1),i+2^j-1] araliginin\n            // cevaplarinin birlesmesiyle elde edilir\n            ST[i][j] = ST[i][j - 1] + ST[i + (1 << (j - 1))][j - 1];\n        }\n\n    return;\n}\n
","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sparse-table/#sorgu-algoritmas","title":"Sorgu Algoritmas\u0131","text":"

Herhangi bir \\([l,r]\\) aral\u0131\u011f\u0131 i\u00e7in sorgu algoritmas\u0131 s\u0131ras\u0131yla \u015fu \u015fekilde \u00e7al\u0131\u015f\u0131r:

  • \\([l,r]\\) aral\u0131\u011f\u0131n\u0131 cevaplar\u0131n\u0131 \u00f6nceden hesaplad\u0131\u011f\u0131m\u0131z aral\u0131klara par\u00e7ala.
    • Sadece \\(2\\)'nin kuvveti uzunlu\u011funda par\u00e7alar\u0131n cevaplar\u0131n\u0131 saklad\u0131\u011f\u0131m\u0131z i\u00e7in aral\u0131\u011f\u0131m\u0131z\u0131 \\(2\\)'nin kuvveti uzunlu\u011funda aral\u0131klara ay\u0131rmal\u0131y\u0131z. \\([l,r]\\) aral\u0131\u011f\u0131n\u0131n uzunlu\u011funun ikilik tabanda yazd\u0131\u011f\u0131m\u0131zda hangi aral\u0131klara par\u00e7alamam\u0131z gerekti\u011fini bulmu\u015f oluruz.
  • Bu aral\u0131klardan gelen cevaplar\u0131 birle\u015ftirerek \\([l,r]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 hesapla.

Herhangi bir aral\u0131\u011f\u0131n uzunlu\u011funun ikilik tabandaki yaz\u0131l\u0131\u015f\u0131ndaki \\(1\\) rakamlar\u0131n\u0131n say\u0131s\u0131 en fazla \\(\\log(N)\\) olabilece\u011finden par\u00e7alayaca\u011f\u0131m\u0131z aral\u0131k say\u0131s\u0131 da en fazla \\(\\log(N)\\) olur. Dolay\u0131s\u0131yla sorgu i\u015flemimiz \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r.

\u00d6rne\u011fin: \\([4,17]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 hesaplamak i\u00e7in algoritmam\u0131z \\([4,17]\\) aral\u0131\u011f\u0131n\u0131 \\([4,11]\\), \\([12,15]\\) ve \\([16,17]\\) aral\u0131klar\u0131na ay\u0131r\u0131r ve bu \\(3\\) aral\u0131ktan gelen cevaplar\u0131 birle\u015ftirerek istenilen cevab\u0131 hesaplar.

// toplam sorgusu\nint query(int l, int r) {\n    int res = 0;\n\n    for (int i = LOG; i >= 0; i--) {\n        // her seferinde uzunlugu r - l + 1 gecmeyecek\n        // en buyuk araligin cevabi ekleyip l'i o araligin sonuna cekiyoruz.\n        if (l + (1 << i) <= r) {\n            res += ST[l][i];\n            l += (1 << i);\n        }\n    }\n\n    return res;\n}\n
","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sparse-table/#minimum-ve-maksimum-sorgu","title":"Minimum ve Maksimum Sorgu","text":"

Sparse Table veri yap\u0131s\u0131n\u0131n di\u011fer veri yap\u0131lar\u0131ndan farkl\u0131 olarak \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda aral\u0131klarda minimum veya maksimum sorgusu yapabilmesi en avantajl\u0131 \u00f6zelli\u011fidir.

Herhangi bir aral\u0131\u011f\u0131n cevab\u0131n\u0131 hesaplarken bu aral\u0131ktaki herhangi bir eleman\u0131 birden fazla kez de\u011ferlendirmemiz cevab\u0131 etkilemez. Bu durum aral\u0131\u011f\u0131m\u0131z\u0131 \\(2\\)'nin kuvveti uzunlu\u011funda maksimum \\(2\\) adet aral\u0131\u011fa b\u00f6lebilmemize ve bu aral\u0131klar\u0131n cevaplar\u0131n\u0131 \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda birle\u015ftirebilmemize olanak sa\u011flar.

int RMQ(int l, int r) {\n    // log[] dizisinde her sayinin onceden hesapadigimiz log2 degerleri saklidir.\n    int j = log[r - l + 1];\n    return min(ST[l][j], ST[r - (1 << j) + 1][j]);\n}\n

Sparse Table veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sqrt-decomposition/","title":"SQRT Decomposition","text":"

Square Root Decomposition algoritmas\u0131 dizi \u00fczerinde \\(\\mathcal{O}(\\sqrt{N})\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda sorgu yapabilmemize ve \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda ise de\u011fi\u015fiklik yapabilmemize olanak sa\u011flayan bir veri yaps\u0131d\u0131r.

","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/sqrt-decomposition/#yaps-ve-kurulusu","title":"Yap\u0131s\u0131 ve Kurulu\u015fu","text":"

Dizinin elemanlar\u0131 her biri yakla\u015f\u0131k \\(\\mathcal{O}(\\sqrt{N})\\) uzunlu\u011funda bloklar halinde par\u00e7alan\u0131r. Her bir blokun cevab\u0131 ayr\u0131 ayr\u0131 hesaplan\u0131r ve bir dizide saklan\u0131r.

Bloklar\u0131n Cevaplar\u0131 \\(21\\) \\(13\\) \\(50\\) \\(32\\) Dizideki Elemanlar \\(3\\) \\(6\\) \\(2\\) \\(10\\) \\(3\\) \\(1\\) \\(4\\) \\(5\\) \\(2\\) \\(7\\) \\(37\\) \\(4\\) \\(11\\) \\(6\\) \\(8\\) \\(7\\) Elemanlar\u0131n \u0130ndeksleri \\(1\\) \\(2\\) \\(3\\) \\(4\\) \\(5\\) \\(6\\) \\(7\\) \\(8\\) \\(9\\) \\(10\\) \\(11\\) \\(12\\) \\(13\\) \\(14\\) \\(15\\) \\(16\\) \u00d6rnek bir dizi \u00fczerinde toplam sorgusu i\u00e7in kurulmu\u015f SQRT Decompostion veri yap\u0131s\u0131.
void build() {\n    for (int i = 1; i <= n; i++) {\n        if (i % sq == 1) { // sq = sqrt(n)\n            t++;           // yeni blok baslangici.\n            st[t] = i;     // t.blok i indisli elemanda baslar.\n        }\n        fn[t] = i;      // t.blokun bitisini i indisli eleman olarak guncelliyoruz.\n        wh[i] = t;      // i indeksli eleman t.blogun icinde.\n        sum[t] += a[i]; // t. blokun cevabina i indeksli elemani ekliyoruz.\n    }\n}\n
","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/sqrt-decomposition/#sorgu-algoritmas","title":"Sorgu Algoritmas\u0131","text":"

Herhangi bir \\([l,r]\\) aral\u0131\u011f\u0131 i\u00e7in sorgu algoritmas\u0131 s\u0131ras\u0131 ile \u015fu \u015fekilde \u00e7al\u0131\u015f\u0131r:

  1. Cevab\u0131n\u0131 arad\u0131\u011f\u0131m\u0131z aral\u0131\u011f\u0131n tamamen kaplad\u0131\u011f\u0131 bloklar\u0131n cevab\u0131n\u0131 cevab\u0131m\u0131za ekliyoruz.
  2. Tamamen kaplamad\u0131\u011f\u0131 bloklardaki aral\u0131\u011f\u0131m\u0131z\u0131n i\u00e7inde olan elemanlar\u0131 tek tek gezerek cevab\u0131m\u0131za ekliyoruz.

Cevab\u0131n\u0131 arad\u0131\u011f\u0131m\u0131z aral\u0131\u011f\u0131n kapsad\u0131\u011f\u0131 blok say\u0131s\u0131 en fazla \\(\\sqrt{N}\\) olabilece\u011finden \\(1.\\) i\u015flem en fazla \\(\\sqrt{N}\\) kez \u00e7al\u0131\u015f\u0131r. Tamamen kaplamad\u0131\u011f\u0131 ancak baz\u0131 elemanlar\u0131 i\u00e7eren en fazla \\(2\\) adet blok olabilir. (Biri en solda di\u011feri en sa\u011fda olacak \u015fekilde.) Bu \\(2\\) blok i\u00e7in de gezmemiz gereken eleman say\u0131s\u0131 maksimum \\(2\\sqrt{N}\\) oldu\u011fundan bir sorgu i\u015fleminde en fazla \\(3\\sqrt{N}\\) i\u015flem yap\u0131l\u0131r, dolay\u0131s\u0131yla sorgu i\u015flemimiz \\(\\mathcal{O}(\\sqrt{N})\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda cal\u0131\u015f\u0131r.

Bloklar\u0131n Cevaplar\u0131 \\(21\\) \\(13\\) \\(50\\) \\(32\\) Dizideki Elemanlar \\(3\\) \\(6\\) \\(2\\) \\(10\\) \\(3\\) \\(1\\) \\(4\\) \\(5\\) \\(2\\) \\(7\\) \\(37\\) \\(4\\) \\(11\\) \\(6\\) \\(8\\) \\(7\\) Elemanlar\u0131n \u0130ndeksleri \\(1\\) \\(2\\) \\(3\\) \\(4\\) \\(5\\) \\(6\\) \\(7\\) \\(8\\) \\(9\\) \\(10\\) \\(11\\) \\(12\\) \\(13\\) \\(14\\) \\(15\\) \\(16\\) \u00d6rnek dizideki \\([3,13]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 \\(2.\\) ve \\(3.\\) bloklar\u0131n cevaplar\u0131 ile \\(3,4\\) ve \\(11\\) indeksli elemanlar\u0131n toplanmas\u0131yla elde edilir.
// [l,r] araligindaki elemanlarin toplamini hesaplayan fonksiyon.\nint query(int l, int r) {\n    int res = 0;\n\n    if (wh[l] == wh[r]) { // l ve r ayni blogun icindeyse\n        for (int i = l; i <= r; i++)\n            res += a[i];\n    } else {\n        for (int i = wh[l] + 1; i <= wh[r] - 1; i++)\n            res += sum[i]; // tamamen kapladigimiz bloklarin cevaplarini ekliyoruz.\n\n        // tamamen kaplamadigimiz bloklardaki araligimiz icindeki\n        // elemanlarin cevaplarini ekliyoruz.\n\n        for (int i = st[wh[l]]; i <= fn[wh[l]]; i++)\n            if (i >= l && i <= r)\n                res += a[i];\n\n        for (int i = st[wh[r]]; i <= fn[wh[r]]; i++)\n            if (i >= l && i <= r)\n                res += a[i];\n    }\n\n    return res;\n}\n
","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/sqrt-decomposition/#eleman-guncelleme-algoritmas","title":"Eleman G\u00fcncelleme Algoritmas\u0131","text":"

Herhangi bir eleman\u0131n de\u011ferini g\u00fcncellerken o eleman\u0131 i\u00e7eren blokun de\u011ferini g\u00fcncellememiz yeterli olacakt\u0131r. Dolay\u0131s\u0131yla g\u00fcncelleme i\u015flemimimiz \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r.

void update(int x, int val) {\n    // x indeksli elemanin yeni degerini val degerine esitliyoruz.\n    sum[wh[x]] -= a[x];\n    a[x] = val;\n    sum[wh[x]] += a[x];\n}\n

SQRT Decomposition veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/stack/","title":"Stack","text":"

Stack veri yap\u0131s\u0131nda elemanlar yap\u0131ya son giren ilk \u00e7\u0131kar (LIFO) kural\u0131na uygun olacak \u015fekilde saklan\u0131r. Bu veri yap\u0131s\u0131nda uygulayabildi\u011fimiz i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcne eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki elemana eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki eleman\u0131 silme.
  • Veri yap\u0131s\u0131n\u0131n bo\u015f olup olmad\u0131\u011f\u0131n\u0131n kontr\u00f6l\u00fc.

C++ dilindeki STL k\u00fct\u00fcphanesinde bulunan haz\u0131r stack yap\u0131s\u0131n\u0131n kullan\u0131m\u0131 a\u015fa\u011f\u0131daki gibidir:

int main() {\n    stack<int> st;\n    cout << st.empty() << endl; // Ilk bashta Stack bosh oldugu icin burada True donecektir.\n    st.push(5);                 // Stack'in en ustune 5'i ekler. Stack'in yeni hali: {5}\n    st.push(7);                 // Stack'in en ustune 7'yi ekler. Stack'in yeni hali: {7, 5}\n    st.push(6);                 // Stack'in en ustune 6'yi ekler. Stack'in yeni hali : {6, 7, 5}\n    st.pop();                   // Stack'in en ustundeki elemani siler. Stack'in yeni hali : {7, 5}\n    st.push(1);                 // Stack'in en ustune 1'i ekler. Stack'in yeni hali : {1, 7, 5}\n    cout << st.top() << endl;   // Stack'in en ustundeki elemana erisir. Ekrana 1 yazirir.\n    cout << st.empty() << endl; // Burada Stack bosh olmadigindan oturu False donecektir.\n}\n
","tags":["Data Structures","Stack"]},{"location":"data-structures/trie/","title":"Trie","text":"

Trie is an efficient information reTrieval data structure. Using Trie, search complexities can be brought to optimal limit (key length). If we store keys in binary search tree, a well balanced BST will need time proportional to \\(M \\times log N\\), where \\(M\\) is maximum string length and \\(N\\) is number of keys in tree. Using Trie, we can search the key in \\(\\mathcal{O}(M)\\) time. However the penalty is on Trie storage requirements (Please refer Applications of Trie for more details)

Trie Structure. https://www.geeksforgeeks.org/wp-content/uploads/Trie.png

Every node of Trie consists of multiple branches. Each branch represents a possible character of keys. We need to mark the last node of every key as end of word node. A Trie node field isEndOfWord is used to distinguish the node as end of word node. A simple structure to represent nodes of English alphabet can be as following,

// Trie node\nclass TrieNode {\n   public:\n    TrieNode *children[ALPHABET_SIZE];\n    bool isEndOfWord;\n    TrieNode() {\n        isEndOfWord = false;\n        for (int i = 0; i < ALPHABET SIZE; i++)\n            children[i] = NULL;\n    }\n};\n
","tags":["Data Structures","Trie"]},{"location":"data-structures/trie/#insertion","title":"Insertion","text":"

Inserting a key into Trie is simple approach. Every character of input key is inserted as an individual Trie node. Note that the children is an array of pointers (or references) to next level Trie nodes. The key character acts as an index into the array children. If the input key is new or an extension of existing key, we need to construct non-existing nodes of the key, and mark end of word for last node. If the input key is prefix of existing key in Trie, we simply mark the last node of key as end of word. The key length determines Trie depth.

void insert(struct TrieNode *root, string key) {\n    struct TrieNode *pCrawl = root;\n    for (int i = 0; i < key.length(); i++) {\n        int index = key[i] - 'a';\n        if (!pCrawl->children[index])\n            pCrawl->children[index] = new TrieNode;\n        pCrawl = pCrawl->children[index];\n    }\n    pCrawl->isEndOfWord = true;\n}\n
","tags":["Data Structures","Trie"]},{"location":"data-structures/trie/#search","title":"Search","text":"

Searching for a key is similar to insert operation, however we only compare the characters and move down. The search can terminate due to end of string or lack of key in Trie. In the former case, if the isEndofWord field of last node is true, then the key exists in Trie. In the second case, the search terminates without examining all the characters of key, since the key is not present in Trie.

bool search(struct TrieNode *root, string key) {\n    TrieNode *pCrawl = root;\n    for (int i = 0; i < key.length(); i++) {\n        int index = key[i] - 'a';\n        if (!pCrawl->children[index])\n            return false;\n        pCrawl = pCrawl->children[index];\n    }\n    return (pCrawl != NULL && pCrawl->isEndOfWord);\n}\n

Insert and search costs \\(\\mathcal{O}(\\text{key\\_length})\\). However the memory requirements of Trie high. It is \\(\\mathcal{O}(\\text{ALPHABET SIZE} \\times \\text{key\\_length} \\times N)\\) where \\(N\\) is number of keys in Trie. There are efficient representation of trie nodes (e.g. compressed trie, ternary search tree, etc.) to minimize memory requirements of trie.

","tags":["Data Structures","Trie"]},{"location":"dynamic-programming/","title":"Dynamic Programming","text":"

Editor: Halil \u00c7etiner

Reviewers: Onur Y\u0131ld\u0131z

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#introduction","title":"Introduction","text":"

Next section is about the Greedy Algorithms and Dynamic Programming. It will be quite a generous introduction to the concepts and will be followed by some common problems.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#greedy-algorithms","title":"Greedy Algorithms","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#dynamic-programming","title":"Dynamic Programming","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#common-dp-problems","title":"Common DP Problems","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#bitmask-dp","title":"Bitmask DP","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#dp-on-rooted-trees","title":"DP on Rooted Trees","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#dp-on-directed-acyclic-graphs","title":"DP on Directed Acyclic Graphs","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#digit-dp","title":"Digit DP","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#walk-counting-using-matrix-exponentiation","title":"Walk Counting using Matrix Exponentiation","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#tree-child-sibling-notation","title":"Tree Child-Sibling Notation","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#references","title":"References","text":"
  1. \"Competitive Programmer\u2019s Handbook\" by Antti Laaksonen - Draft July 3, 2018
  2. Wikipedia - Dynamic Programming
  3. Topcoder - Competitive Programming Community / Dynamic Programming from Novice to Advanced
  4. Hacker Earth - Dynamic Programming
  5. Geeks for Geeks - Dynamic Programming
","tags":["Dynamic Programming"]},{"location":"dynamic-programming/bitmask-dp/","title":"Bitmask DP","text":"","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#what-is-bitmask","title":"What is Bitmask?","text":"

Let\u2019s say that we have a set of objects. How can we represent a subset of this set? One way is using a map and mapping each object with a Boolean value indicating whether the object is picked. Another way is, if the objects can be indexed by integers, we can use a Boolean array. However, this can be slow due to the operations of the map and array structures. If the size of the set is not too large (less than 64), a bitmask is much more useful and convenient.

An integer is a sequence of bits. Thus, we can use integers to represent a small set of Boolean values. We can perform all the set operations using bit operations. These bit operations are faster than map and array operations, and the time difference may be significant in some problems.

In a bitmask, the \\( i \\)-th bit from the right represents the \\( i \\)-th object. For example, let \\( A = \\{1, 2, 3, 4, 5\\} \\), we can represent \\( B = \\{1, 2, 4\\} \\) with the 11 (01011) bitmask.

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#bitmask-operations","title":"Bitmask Operations","text":"
  • Add the \\( i \\)-th object to the subset: Set the \\( i \\)-th bit to 1: \\( \\text{mask } = \\text{mask } | \\text{ } (1 << i) \\)

  • Remove the \\( i \\)-th object from the subset: Set the \\( i \\)-th bit to 0: \\( \\text{mask } = \\text{mask } \\& \\sim (1 << i) \\)

  • Check whether the \\( i \\)-th object is in the subset: Check if the \\( i \\)-th bit is set: \\( \\text{mask } \\& \\text{ } (1 << i) \\). If the expression is equal to 1, the \\( i \\)-th object is in the subset. If the expression is equal to 0, the \\( i \\)-th object is not in the subset.

  • Toggle the existence of the \\( i \\)-th object: XOR the \\( i \\)-th bit with 1, turning 1 into 0 and 0 into 1: \\( \\text{mask} = \\text{mask}\\) ^ \\( (1 << i) \\)

  • Count the number of objects in the subset: Use a built-in function to count the number of 1\u2019s in an integer variable: __builtin_popcount(mask) for integers or __builtin_popcountll(mask) for long longs.

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#iterating-over-subsets","title":"Iterating Over Subsets","text":"
  • Iterate through all subsets of a set with size \\( n \\): \\( \\text{for (int x = 0; x < (1 << n); ++x)} \\)

  • Iterate through all subsets of a subset with the mask \\( y \\): \\( \\text{for (int x = y; x > 0; x = (y \\& (x \u2212 1)))} \\)

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#task-assignment-problem","title":"Task Assignment Problem","text":"

There are \\( N \\) people and \\( N \\) tasks, and each task is going to be allocated to a single person. We are also given a matrix cost of size \\( N \\times N \\), where cost[i][j] denotes how much a person is going to charge for a task. We need to assign each task to a person such that the total cost is minimized. Note that each task is allocated to only one person, and each person is allocated only one task.

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#naive-approach","title":"Naive Approach:","text":"

Try \\( N! \\) possible assignments. Time complexity: \\( O(N!) \\).

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#dp-approach","title":"DP Approach:","text":"

For every possible subset, find the new subsets that can be generated from it and update the DP array. Here, we use bitmasking to represent subsets and iterate over them. Time complexity: \\( O(2^N \\times N) \\).

Note: The Hungarian Algorithm solves this problem in \\( O(N^3) \\) time complexity.

Solution code for DP approach:

for (int mask = 0; mask < (1 << n); ++mask)\n{\n    for (int j = 0; j < n; ++j)\n    {\n        if((mask & (1 << j)) == 0) // jth task not assigned\n        {\n            dp[mask | (1 << j)] = min(dp[mask | (1 << j)], dp[mask] + cost[__builtin_popcount(mask)][j])\n        }\n    }\n}\n// after this operation our answer stored in dp[(1 << N) - 1]\n
","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#references","title":"References","text":"
  • Bitmask Tutorial on HackerEarth
","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/common-dp-problems/","title":"Common Dynamic Programming Problems","text":"","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#coin-problem","title":"Coin Problem","text":"

As discussed earlier, the Greedy approach doesn\u2019t work all the time for the coin problem. For example, if the coins are {4, 3, 1} and the target sum is \\(6\\), the greedy algorithm produces the solution \\(4+1+1\\), while the optimal solution is \\(3+3\\). This is where Dynamic Programming (DP) helps.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#solution","title":"Solution","text":"","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#approach","title":"Approach:","text":"
  1. If \\( V == 0 \\), then 0 coins are required.
  2. If \\( V > 0 \\), compute \\( \\text{minCoins}(coins[0..m-1], V) = \\min \\{ 1 + \\text{minCoins}(V - \\text{coin}[i]) \\} \\) for all \\( i \\) where \\( \\text{coin}[i] \\leq V \\).
def minCoins(coins, target):\n    # base case\n    if (V == 0):\n        return 0\n\n    n = len(coins)\n    # Initialize result\n    res = sys.maxsize\n\n    # Try every coin that has smaller value than V\n    for i in range(0, n):\n        if (coins[i] <= target):\n            sub_res = minCoins(coins, target-coins[i])\n\n    # Check for INT_MAX to avoid overflow and see if\n    # result can minimized\n    if (sub_res != sys.maxsize and sub_res + 1 < res):\n        res = sub_res + 1\n\n    return res\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#knapsack-problem","title":"Knapsack Problem","text":"

We are given the weights and values of \\( n \\) items, and we are to put these items in a knapsack of capacity \\( W \\) to get the maximum total value. In other words, we are given two integer arrays val[0..n-1] and wt[0..n-1], which represent the values and weights associated with \\( n \\) items. We are also given an integer \\( W \\), which represents the knapsack's capacity. Our goal is to find out the maximum value subset of val[] such that the sum of the weights of this subset is smaller than or equal to \\( W \\). We cannot break an item; we must either pick the complete item or leave it.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#approach_1","title":"Approach:","text":"

There are two cases for every item: 1. The item is included in the optimal subset. 2. The item is not included in the optimal subset.

The maximum value that can be obtained from \\( n \\) items is the maximum of the following two values: 1. Maximum value obtained by \\( n-1 \\) items and \\( W \\) weight (excluding the \\( n \\)-th item). 2. Value of the \\( n \\)-th item plus the maximum value obtained by \\( n-1 \\) items and \\( W - \\text{weight of the } n \\)-th item (including the \\( n \\)-th item).

If the weight of the \\( n \\)-th item is greater than \\( W \\), then the \\( n \\)-th item cannot be included, and case 1 is the only possibility.

For example:

  • Knapsack max weight: \\( W = 8 \\) units
  • Weight of items: \\( \\text{wt} = \\{3, 1, 4, 5\\} \\)
  • Values of items: \\( \\text{val} = \\{10, 40, 30, 50\\} \\)
  • Total items: \\( n = 4 \\)

The sum \\( 8 \\) is possible with two combinations: {3, 5} with a total value of 60, and {1, 3, 4} with a total value of 80. However, a better solution is {1, 5}, which has a total weight of 6 and a total value of 90.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#recursive-solution","title":"Recursive Solution","text":"
def knapSack(W , wt , val , n):\n\n    # Base Case\n    if (n == 0 or W == 0):\n        return 0\n\n    # If weight of the nth item is more than Knapsack of capacity\n    # W, then this item cannot be included in the optimal solution\n    if (wt[n-1] > W):\n        return knapSack(W, wt, val, n - 1)\n\n    # return the maximum of two cases:\n    # (1) nth item included\n    # (2) not included\n    else:\n        return max(val[n-1] + knapSack(W - wt[n - 1], wt, val, n - 1), knapSack(W, wt, val, n - 1))\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#dynamic-programming-solution","title":"Dynamic Programming Solution","text":"

It should be noted that the above function computes the same subproblems again and again. Time complexity of this naive recursive solution is exponential \\(2^n\\). Since suproblems are evaluated again, this problem has Overlapping Subproblems property. Like other typical Dynamic Programming(DP) problems, recomputations of same subproblems can be avoided by constructing a temporary array \\(K[][]\\) in bottom up manner. Following is Dynamic Programming based implementation.

def knapSack(W, wt, val, n):\n    K = [[0 for x in range(W + 1)] for x in range(n + 1)]\n\n    # Build table K[][] in bottom up manner\n    for (i in range(n + 1)):\n        for (w in range(W + 1)):\n            if (i == 0 or w == 0):\n                K[i][w] = 0\n            elif (wt[i - 1] <= w):\n                K[i][w] = max(val[i - 1] + K[i - 1][w - wt[i - 1]], K[i - 1][w])\n            else:\n                K[i][w] = K[i - 1][w]\n\n    return K[n][W]\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#longest-common-substring-lcs-problem","title":"Longest Common Substring (LCS) Problem","text":"

We are given two strings \\( X \\) and \\( Y \\), and our task is to find the length of the longest common substring.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#sample-case","title":"Sample Case:","text":"
  • Input: \\( X = \"inzvahackerspace\" \\), \\( Y = \"spoilerspoiler\" \\)
  • Output: 4

The longest common substring is \"ersp\" and is of length 4.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#approach_2","title":"Approach:","text":"

Let \\( m \\) and \\( n \\) be the lengths of the first and second strings, respectively. A simple solution is to consider all substrings of the first string one by one and check if they are substrings of the second string. Keep track of the maximum-length substring. There will be \\( O(m^2) \\) substrings, and checking if one is a substring of the other will take \\( O(n) \\) time. Thus, the overall time complexity is \\( O(n \\cdot m^2) \\).

Dynamic programming can reduce this to \\( O(m \\cdot n) \\). The idea is to find the length of the longest common suffix for all substrings of both strings and store these lengths in a table. The longest common suffix has the following property:

[ LCSuff(X, Y, m, n) = LCSuff(X, Y, m-1, n-1) + 1 \\text{ if } X[m-1] = Y[n-1] ] Otherwise, \\( LCSuff(X, Y, m, n) = 0 \\).

The maximum length of the Longest Common Suffix is the Longest Common Substring.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#dp-iterative","title":"DP - Iterative","text":"
def LCSubStr(X, Y):\n    m = len(X)\n    n = len(Y)\n\n    # Create a table to store lengths of\n    # longest common suffixes of substrings.\n    # Note that LCSuff[i][j] contains the\n    # length of longest common suffix of\n    # X[0...i\u22121] and Y[0...j\u22121]. The first\n    # row and first column entries have no\n    # logical meaning, they are used only\n    # for simplicity of the program.\n\n    # LCSuff is the table with zero\n    # value initially in each cell\n    LCSuff = [[0 for k in range(n+1)] for l in range(m + 1)]\n\n    # To store the length of\n    # longest common substring\n    result = 0\n\n    # Following steps to build\n    # LCSuff[m+1][n+1] in bottom up fashion\n    for (i in range(m + 1)):\n        for (j in range(n + 1)):\n    if (i == 0 or j == 0):\n                LCSuff[i][j] = 0\n            elif (X[i - 1] == Y[j - 1]):\n                LCSuff[i][j] = LCSuff[i - 1][j - 1] + 1\n                result = max(result, LCSuff[i][j])\n            else:\n                LCSuff[i][j] = 0\n    return result\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#dp-recursive","title":"DP - Recursive","text":"
def lcs(int i, int j, int count):\n    if (i == 0 or j == 0):\n        return count\n\n    if (X[i - 1] == Y[j - 1]):\n        count = lcs(i - 1, j - 1, count + 1)\n\n    count = max(count, max(lcs(i, j - 1, 0), lcs(i - 1, j, 0)))\n    return count\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#longest-increasing-subsequence-lis-problem","title":"Longest Increasing Subsequence (LIS) Problem","text":"

The Longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

For example, given the array \\([0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]\\), the longest increasing subsequence has a length of 6, and it is {0, 2, 6, 9, 11, 15}.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#solution_1","title":"Solution","text":"

A naive, brute-force approach is to generate every possible subsequence, check for monotonicity, and keep track of the longest one. However, this is prohibitively expensive, as generating each subsequence takes \\( O(2^N) \\) time.

Instead, we can use recursion to solve this problem and then optimize it with dynamic programming. We assume that we have a function that gives us the length of the longest increasing subsequence up to a certain index.

The base cases are: - The empty list, which returns 0. - A list with one element, which returns 1.

For every index \\( i \\), calculate the longest increasing subsequence up to that point. The result can only be extended with the last element if the last element is greater than \\( \\text{arr}[i] \\), as otherwise, the sequence wouldn\u2019t be increasing.

def longest_increasing_subsequence(arr):\n    if (not arr):\n        return 0\n    if (len(arr) == 1):\n        return 1\n\n    max_ending_here = 0\n    for (i in range(len(arr))):\n        ending_at_i = longest_increasing_subsequence(arr[:i])\n        if (arr[-1] > arr[i - 1] and ending_at_i + 1 > max_ending_here):\n            max_ending_here = ending_at_i + 1\n    return max_ending_here\n

This is really slow due to repeated subcomputations (exponential in time). So, let\u2019s use dynamic programming to store values to recompute them for later.

We\u2019ll keep an array A of length N, and A[i] will contain the length of the longest increasing subsequence ending at i. We can then use the same recurrence but look it up in the array instead:

def longest_increasing_subsequence(arr):\n    if (not arr):\n        return 0\n    cache = [1] * len(arr)\n    for (i in range(1, len(arr))):\n        for (j in range(i)):\n            if (arr[i] > arr[j]):\n                cache[i] = max(cache[i], cache[j] + 1)\n    return max(cache)\n

This now runs in \\( O(N^2) \\) time and \\( O(N) \\) space.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/digit-dp/","title":"Digit DP","text":"

Problems that require the calculation of how many numbers there are between two values (say, \\( A \\) and \\( B \\)) that satisfy a particular property can be solved using digit dynamic programming (Digit DP).

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#how-to-work-on-digits","title":"How to Work on Digits","text":"

While constructing our numbers recursively (from the left), we need a method to check if our number is still smaller than the given boundary number. To achieve this, we keep a variable called \"strict\" while branching, which limits our ability to select digits that are larger than the corresponding digit of the boundary number.

Let\u2019s suppose the boundary number is \\( A \\). We start filling the number from the left (most significant digit) and set strict to true, meaning we cannot select any digit larger than the corresponding digit of \\( A \\). As we branch:

  • Values less than the corresponding digit of \\( A \\) will now be non-strict (strict = false) because we guarantee that the number will be smaller than \\( A \\) after this point.
  • For values equal to the corresponding digit of \\( A \\), the strictness continues to be true.
","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#counting-problem-example","title":"Counting Problem Example","text":"

Problem: How many numbers \\( x \\) are there in the range \\( A \\) to \\( B \\), where the digit \\( d \\) occurs exactly \\( k \\) times in \\( x \\)?

Constraints: \\( A, B < 10^{60}, k < 60 \\).

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#brute-force-approach","title":"Brute Force Approach:","text":"

The brute-force solution would involve iterating over all the numbers in the range \\([A, B]\\) and counting the occurrences of the digit \\( d \\) one by one for each number. This has a time complexity of \\( O(N \\log_{10}(N)) \\), which is too large for such constraints, and we need a more efficient approach.

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#recursive-approach","title":"Recursive Approach:","text":"

We can recursively fill the digits of our number starting from the leftmost digit. At each step, we branch into 3 possibilities:

  1. Pick a number that is not \\( d \\) and smaller than the corresponding digit of the boundary number.
  2. Pick the digit \\( d \\).
  3. Pick a number that is equal to the corresponding digit of the boundary number.

The depth of recursion is equal to the number of digits in the decimal representation of the boundary number, leading to a time complexity of \\( O(3^{\\log_{10} N}) \\). Although this is better than brute force, it is still not efficient enough.

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#recursive-approach-with-memoization","title":"Recursive Approach with Memoization:","text":"

We can further optimize this approach using memoization. We represent a DP state by \\((\\text{current index}, \\text{current strictness}, \\text{number of } d's)\\), which denotes the number of possible configurations of the remaining digits after picking the current digit. We use a dp[\\log_{10} N][2][\\log_{10} N] array, where each value is computed at most once. Therefore, the worst-case time complexity is \\( O((\\log_{10} N)^2) \\).

Solution Code:

#include <bits/stdc++.h>\nusing namespace std;\n#define ll long long\nll A, B, d, k, dg; // dg: digit count\nvector <ll> v; // digit vector\nll dp[25][2][25];\nvoid setup(ll a)\n{\n    memset(dp,0,sizeof dp);\n    v.clear();\n    ll tmp = a;\n    while(tmp)\n    {\n        v.push_back(tmp%10);\n        tmp/=10;\n    }\n    dg = (ll)v.size();\n    reverse(v.begin(), v.end());\n}\n\nll rec(int idx, bool strict, int count)\n{\n    if(dp[idx][strict][count]) return dp[idx][strict][count];\n    if(idx == dg or count > k) return (count == k);\n    ll sum = 0;\n    if(strict)\n    {\n        // all <v[idx] if d is included -1\n        sum += rec(idx + 1, 0, count) * (v[idx] - (d < v[idx]));\n        // v[idx], if d==v[idx] send count+1\n        sum += rec(idx + 1, 1, count + (v[idx] == d) );\n        if(d < v[idx])\n        sum += rec(idx + 1, 0, count + 1); // d\n    }\n    else\n    {\n        sum += rec(idx + 1, 0, count) * (9); // other than d (10 - 1)\n        sum += rec(idx + 1, 0, count + 1); // d\n    }\n    return dp[idx][strict][count] = sum;\n}\n\nint main()\n{\n    cin >> A >> B >> d >> k;\n    setup(B);\n    ll countB = rec(0, 1, 0); //countB is answer of [0..B]\n    setup(A - 1);\n    ll countA = rec(0, 1, 0); //countA is answer of [0..A-1]\n    cout << fixed << countB - countA << endl; //difference gives us [A..B]\n}\n
","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#references","title":"References","text":"
  • Digit DP on Codeforces

  • Digit DP on HackerRank

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/dp-on-dags/","title":"DP on Directed Acyclic Graphs (DAGs)","text":"

As we know, the nodes of a directed acyclic graph (DAG) can be sorted topologically, and DP can be implemented efficiently using this topological order.

First, we can find the topological order with a topological sort in \\( O(N) \\) time complexity. Then, we can find the \\( dp(V) \\) values in topological order, where \\( V \\) is a node in the DAG and \\( dp(V) \\) is the answer for node \\( V \\). The answer and implementation will differ depending on the specific problem.

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#converting-a-dp-problem-into-a-directed-acyclic-graph","title":"Converting a DP Problem into a Directed Acyclic Graph","text":"

Many DP problems can be converted into a DAG. Let\u2019s explore why this is the case.

While solving a DP problem, when we process a state, we evaluate it by considering all possible previous states. To do this, all of the previous states must be processed before the current state. From this perspective, some states depend on other states, forming a DAG structure.

However, note that some DP problems cannot be converted into a DAG and may require hyper-graphs. (For more details, refer to Advanced Dynamic Programming in Semiring and Hypergraph Frameworks).

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#example-problem","title":"Example Problem:","text":"

There are \\( N \\) stones numbered \\( 1, 2, ..., N \\). For each \\( i \\) ( \\( 1 \\leq i \\leq N \\) ), the height of the \\( i \\)-th stone is \\( h_i \\). There is a frog initially on stone 1. The frog can jump to stone \\( i+1 \\) or stone \\( i+2 \\). The cost of a jump from stone \\( i \\) to stone \\( j \\) is \\( | h_i \u2212 h_j | \\). Find the minimum possible cost to reach stone \\( N \\).

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#solution","title":"Solution:","text":"

We define \\( dp[i] \\) as the minimum cost to reach the \\( i \\)-th stone. The answer will be \\( dp[N] \\). The recurrence relation is defined as:

\\[ dp[i] = \\min(dp[i\u22121] + |h_i \u2212 h_{i\u22121}|, dp[i\u22122] + |h_i \u2212 h_{i\u22122}|) \\]

For \\( N = 5 \\), we can see that to calculate \\( dp[5] \\), we need to calculate \\( dp[4] \\) and \\( dp[3] \\). Similarly:

  • \\( dp[4] \\) depends on \\( dp[3] \\) and \\( dp[2] \\),
  • \\( dp[3] \\) depends on \\( dp[2] \\) and \\( dp[1] \\),
  • \\( dp[2] \\) depends on \\( dp[1] \\).

These dependencies form a DAG, where the nodes represent the stones, and the edges represent the transitions between them based on the jumps.

graph LR\n    A(dp_1) --> B(dp_2);\n    A --> C(dp_3);\n    B --> D(dp_4);\n    B --> E(dp_5);\n    C --> D;\n    D --> E;
","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#dp-on-directed-acyclic-graph-problem","title":"DP on Directed Acyclic Graph Problem","text":"

Given a DAG with \\( N \\) nodes and \\( M \\) weighted edges, find the longest path in the DAG.

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#complexity","title":"Complexity:","text":"

The time complexity for this problem is \\( O(N + M) \\), where \\( N \\) is the number of nodes and \\( M \\) is the number of edges.

Solution Code:

// topological sort is not written here so we will take tp as it is already sorted\n// note that tp is reverse topologically sorted\n// vector <int> tp\n// n , m and vector <pair<int,int>> adj is given.Pair denotes {node,weight}.\n// flag[] denotes whether a node is processed or not.Initially all zero.\n// dp[] is DP array.Initially all zero.\n\nfor (int i = 0; i < (int)tp.size(); ++i)//processing in order\n{\n    int curNode = tp[i];\n\n    for (auto v : adj[curNode]) //iterate through all neighbours\n        if(flag[v.first]) //if a neighbour is already processed\n            dp[curNode] = max(dp[curNode] , dp[v.first] + v.second);\n\n    flag[curNode] = 1;\n}\n//answer is max(dp[1..n])\n
","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#references","title":"References","text":"
  • NOI IOI training week-5

  • DP on Graphs MIT

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-rooted-trees/","title":"DP on Rooted Trees","text":"

In dynamic programming (DP) on rooted trees, we define functions for the nodes of the tree, which are calculated recursively based on the children of each node. One common DP state is usually associated with a node \\(i\\), representing the sub-tree rooted at node \\(i\\).

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#problem","title":"Problem","text":"

Given a tree \\( T \\) of \\( N \\) (1-indexed) nodes, where each node \\( i \\) has \\( C_i \\) coins attached to it, the task is to choose a subset of nodes such that no two adjacent nodes (nodes directly connected by an edge) are chosen, and the sum of coins attached to the chosen subset is maximized.

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#approach","title":"Approach:","text":"

We define two functions, \\( dp1(V) \\) and \\( dp2(V) \\), as follows:

  • \\( dp1(V) \\): The optimal solution for the sub-tree of node \\( V \\) when node \\( V \\) is included in the answer.
  • \\( dp2(V) \\): The optimal solution for the sub-tree of node \\( V \\) when node \\( V \\) is not included in the answer.

The final answer is the maximum of these two cases:

\\[ \\text{max}(dp1(V), dp2(V)) \\]

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#recursive-definitions","title":"Recursive Definitions:","text":"
  • \\( dp1(V) = C_V + \\sum_{i=1}^{n} dp2(v_i) \\), where \\( n \\) is the number of children of node \\( V \\), and \\( v_i \\) is the \\( i \\)-th child of node \\( V \\). This represents the scenario where node \\( V \\) is included in the chosen subset, so none of its children can be selected.

  • \\( dp2(V) = \\sum_{i=1}^{n} \\text{max}(dp1(v_i), dp2(v_i)) \\). This represents the scenario where node \\( V \\) is not included, so the optimal solution for each child \\( v_i \\) can either include or exclude that child.

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#complexity","title":"Complexity:","text":"

The time complexity for this approach is \\( O(N) \\), where \\( N \\) is the number of nodes in the tree. This is because the solution involves a depth-first search (DFS) traversal of the tree, and each node is visited only once.

//pV is parent of V\nvoid dfs(int V, int pV)\n{\n    //base case:\n    //when dfs reaches a leaf it finds dp1 and dp2 and does not branch again.\n\n    //for storing sums of dp1 and max(dp1, dp2) for all children of V\n    int sum1 = 0, sum2 = 0;\n\n    //traverse over all children\n    for (auto v : adj[V])\n    {\n        if (v == pV)\n            continue;\n        dfs(v, V);\n        sum1 += dp2[v];\n        sum2 += max(dp1[v], dp2[v]);\n    }\n\n    dp1[V] = C[V] + sum1;\n    dp2[V] = sum2;\n}\n//Nodes are 1-indexed, therefore our answer stored in dp1[1] and dp2[1]\n//for the answer we take max(dp1[1],dp2[1]) after calling dfs(1,0).\n
","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#references","title":"References","text":"
  • DP on Tree on CodeForces
","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dynamic-programming/","title":"Dynamic Programming","text":"

Dynamic programming (DP) is a technique used to avoid computing the same sub-solution multiple times in a recursive algorithm. A sub-solution of the problem is constructed from the previously found ones. DP solutions have a polynomial complexity, which ensures a much faster running time than other techniques like backtracking or brute-force.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#memoization-top-down","title":"Memoization - Top Down","text":"

Memoization ensures that a method doesn\u2019t run for the same inputs more than once by keeping a record of the results for the given inputs (usually in a hash map).

To avoid duplicate work caused by recursion, we can use a cache that maps inputs to outputs. The approach involves:

  • Checking the cache to see if we can avoid computing the answer for any given input.
  • Saving the results of any calculations to the cache.

Memoization is a common strategy for dynamic programming problems where the solution is composed of solutions to the same problem with smaller inputs, such as the Fibonacci problem.

Another strategy for dynamic programming is the bottom-up approach, which is often cleaner and more efficient.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#bottom-up","title":"Bottom-Up","text":"

The bottom-up approach avoids recursion, saving the memory cost associated with building up the call stack. It \"starts from the beginning\" and works towards the final solution, whereas a recursive algorithm often \"starts from the end and works backwards.\"

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#an-example-fibonacci","title":"An Example - Fibonacci","text":"

Let\u2019s start with a well-known example: finding the \\(n\\)-th Fibonacci number. The Fibonacci sequence is defined as:

\\[ F_n = F_{n\u22121} + F_{n\u22122}, \\quad \\text{with } F_0 = 0 \\text{ and } F_1 = 1 \\]

There are several approaches to solving this problem:

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#recursion","title":"Recursion","text":"

In a recursive approach, the function calls itself to compute the previous two Fibonacci numbers until reaching the base cases.

def fibonacci(n):\n    if (n == 0):\n        return 0\n    if (n == 1):\n        return 1\n\n    return fibonacci(n - 1) + fibonacci(n - 2)\n
","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#dynamic-programming","title":"Dynamic Programming","text":"
  • Top-Down - Memoization: Recursion leads to unnecessary repeated calculations. Memoization solves this by caching the results of previously computed Fibonacci numbers, so they don't have to be recalculated.
cache = {}\n\ndef fibonacci(n):\n    if (n == 0):\n        return 0\n    if (n == 1):\n        return 1\n    if (n in cache):\n        return cache[n]\n\n    cache[n] = fibonacci(n - 1) + fibonacci(n - 2)\n\n    return cache[n]\n
Visualization of Recursive Memoization
  • Bottom-Up: The bottom-up approach eliminates recursion by computing the Fibonacci numbers in order, starting from the base cases and building up to the desired value.
cache = {}\n\ndef fibonacci(n):\n    cache[0] = 0\n    cache[1] = 1\n\n    for (i in range(2, n + 1)):\n        cache[i] = cache[i - 1] + cache[i - 2]\n\n    return cache[n]\n

Additionally, this approach can be optimized further by using constant space and only storing the necessary partial results along the way.

def fibonacci(n):\n    fib_minus_2 = 0\n    fib_minus_1 = 1\n\n    for (i in range(2, n + 1)):\n        fib = fib_minus_1 + fib_minus_2\n        fib_minus_1, fib_minus_2 = fib, fib_minus_1\n\n    return fib\n
","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#how-to-apply-dynamic-programming","title":"How to Apply Dynamic Programming?","text":"

To apply dynamic programming, follow these steps:

  • Find the recursion in the problem: Identify how the problem can be broken down into smaller subproblems.
  • Top-down approach: Store the result of each subproblem in a table to avoid recomputation.
  • Bottom-up approach: Find the correct order to evaluate the results so that partial results are available when needed.

Dynamic programming generally works for problems that have an inherent left-to-right order, such as strings, trees, or integer sequences. If the naive recursive algorithm does not compute the same subproblem multiple times, dynamic programming won't be useful.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/greedy-algorithms/","title":"Greedy Algorithms","text":"

A greedy algorithm is an algorithm that follows the problem solving heuristic of making the locally optimal choice at each stage with the hope of finding a global optimum. A greedy algorithm never takes back its choices, but directly constructs the final solution. For this reason, greedy algorithms are usually very efficient.

The difficulty in designing greedy algorithms is to find a greedy strategy that always produces an optimal solution to the problem. The locally optimal choices in a greedy algorithm should also be globally optimal. It is often difficult to argue that a greedy algorithm works.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#coin-problem","title":"Coin Problem","text":"

We are given a value \\( V \\). If we want to make change for \\( V \\) cents, and we have an infinite supply of each of the coins = { \\( C_1, C_2, \\dots, C_m \\) } valued coins (sorted in descending order), what is the minimum number of coins to make the change?

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#solution","title":"Solution","text":"","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#approach","title":"Approach:","text":"
  1. Initialize the result as empty.
  2. Find the largest denomination that is smaller than the amount.
  3. Add the found denomination to the result. Subtract the value of the found denomination from the amount.
  4. If the amount becomes 0, then print the result. Otherwise, repeat steps 2 and 3 for the new value of the amount.

def min_coins(coins, amount):\n    n = len(coins)\n    for i in range(n):\n        while amount >= coins[i]:\n            # while loop is needed since one coin can be used multiple times\n            amount -= coins[i]\n            print(coins[i])\n
For example, if the coins are the euro coins (in cents) \\({200, 100, 50, 20, 10, 5, 2, 1}\\) and the amount is 548, the optimal solution is to select coins \\(200+200+100+20+20+5+2+1\\), whose sum is \\(548\\).

Visualization of the Coin Change Problem

In the general case, the coin set can contain any kind of coins, and the greedy algorithm does not necessarily produce an optimal solution.

We can prove that a greedy algorithm does not work by showing a counterexample where the algorithm gives a wrong answer. In this problem, we can easily find a counterexample: if the coins are \\({6, 5, 2}\\) and the target sum is \\(10\\), the greedy algorithm produces the solution \\(6+2+2\\), while the optimal solution is \\(5+5\\).

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#scheduling","title":"Scheduling","text":"

Many scheduling problems can be solved using greedy algorithms. A classic problem is as follows:

We are given an array of jobs where every job has a deadline and associated profit if the job is finished before the deadline. It is also given that every job takes a single unit of time, thus the minimum possible deadline for any job is 1. How do we maximize total profit if only one job can be scheduled at a time?

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#solution_1","title":"Solution","text":"

A simple solution is to generate all subsets of the given set of jobs and check each subset for feasibility. Keep track of maximum profit among all feasible subsets. The time complexity of this solution is exponential. This is a standard Greedy Algorithm problem.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#approach_1","title":"Approach:","text":"
  1. Sort all jobs in decreasing order of profit.
  2. Initialize the result sequence as the first job in sorted jobs.
  3. For the remaining \\(n-1\\) jobs:
  4. If the current job can fit in the current result sequence without missing the deadline, add the current job to the result.
  5. Else ignore the current job.
# sample job : ['x', 4, 25] \u2212> [job_id, deadline, profit]\n# jobs: array of 'job's\ndef print_job_scheduling(jobs, t):\n    n = len(jobs)\n\n    # Sort all jobs according to decreasing order of profit\n    for i in range(n):\n        for j in range(n - 1 - i):\n            if jobs[j][2] < jobs[j + 1][2]:\n                jobs[j], jobs[j + 1] = jobs[j + 1], jobs[j]\n\n    # To keep track of free time slots\n    result = [False] * t\n    # To store result (Sequence of jobs)\n    job = ['-1'] * t\n\n    # Iterate through all given jobs\n    for i in range(len(jobs)):\n        # Find a free slot for this job\n        # (Note that we start from the last possible slot)\n        for j in range(min(t - 1, jobs[i][1] - 1), -1, -1):\n            # Free slot found\n            if result[j] is False:\n                result[j] = True\n                job[j] = jobs[i][0]\n                break\n    print(job)\n
","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#tasks-and-deadlines","title":"Tasks and Deadlines","text":"

Let us now consider a problem where we are given \\(n\\) tasks with durations and deadlines, and our task is to choose an order to perform the tasks. For each task, we earn \\(d - x\\) points, where \\(d\\) is the task\u2019s deadline and \\(x\\) is the moment when we finish the task. What is the largest possible total score we can obtain?

For example, suppose the tasks are as follows:

Task Duration Deadline A 4 2 B 3 5 C 2 7 D 4 5

An optimal schedule for the tasks is \\( C, B, A, D \\). In this solution, \\( C \\) yields 5 points, \\( B \\) yields 0 points, \\( A \\) yields -7 points, and \\( D \\) yields -8 points, so the total score is -10.

Interestingly, the optimal solution to the problem does not depend on the deadlines, but a correct greedy strategy is to simply perform the tasks sorted by their durations in increasing order.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#solution_2","title":"Solution","text":"
  1. Sort all tasks according to increasing order of duration.
  2. Calculate the total points by iterating through all tasks, summing up the difference between the deadlines and the time at which the task is finished.
def order_tasks(tasks):\n    n = len(tasks)\n\n    # Sort all task according to increasing order of duration\n    for (i in range(n)):\n        for (j in range(n - 1 - i)):\n            if (tasks[j][1] > tasks[j + 1][1]):\n                tasks[j], tasks[j + 1] = tasks[j + 1], tasks[j]\n\n    point = 0\n    current_time = 0\n    # Iterate through all given tasks and calculate point\n    for (i in range(len(tasks))):\n        current_time = current_time + tasks[i][1]\n        point = point + (tasks[i][2] - current_time)\n\n    print(point)\n
","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#minimizing-sums","title":"Minimizing Sums","text":"

We are given \\(n\\) numbers and our task is to find a value \\(x\\) that minimizes the sum:

\\[ |a_1 \u2212 x|^c + |a_2 \u2212 x|^c + ... + |a_n \u2212 x|^c \\]

We focus on the cases \\(c = 1\\) and \\(c = 2\\).

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#case-c-1","title":"Case \\(c = 1\\)","text":"

In this case, we should minimize the sum:

\\[ |a_1 \u2212 x| + |a_2 \u2212 x| + ... + |a_n \u2212 x| \\]

For example, if the numbers are \\([1, 2, 9, 2, 6]\\), the best solution is to select \\(x = 2\\), which produces the sum:

\\[ |1 \u2212 2| + |2 \u2212 2| + |9 \u2212 2| + |2 \u2212 2| + |6 \u2212 2| = 12 \\]

In the general case, the best choice for \\(x\\) is the median of the numbers. For instance, the list \\([1, 2, 9, 2, 6]\\) becomes \\([1, 2, 2, 6, 9]\\) after sorting, so the median is 2. The median is an optimal choice because if \\(x\\) is smaller than the median, the sum decreases by increasing \\(x\\), and if \\(x\\) is larger, the sum decreases by lowering \\(x\\). Hence, the optimal solution is \\(x = \\text{median}\\).

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#case-c-2","title":"Case \\(c = 2\\)","text":"

In this case, we minimize the sum:

\\[ (a_1 \u2212 x)^2 + (a_2 \u2212 x)^2 + ... + (a_n \u2212 x)^2 \\]

For example, if the numbers are \\([1, 2, 9, 2, 6]\\), the best solution is to select \\(x = 4\\), which produces the sum:

\\[ (1 \u2212 4)^2 + (2 \u2212 4)^2 + (9 \u2212 4)^2 + (2 \u2212 4)^2 + (6 \u2212 4)^2 = 46 \\]

In the general case, the best choice for \\(x\\) is the average of the numbers. For the given example, the average is:

\\[ \\frac{(1 + 2 + 9 + 2 + 6)}{5} = 4 \\]

This result can be derived by expressing the sum as:

\\[ n x^2 \u2212 2x(a_1 + a_2 + ... + a_n) + (a_1^2 + a_2^2 + ... + a_n^2) \\]

The last part does not depend on \\(x\\), so we can ignore it. The remaining terms form a function with a parabola opening upwards, and the minimum value occurs at \\(x = \\frac{s}{n}\\), where \\(s\\) is the sum of the numbers, i.e., the average of the numbers.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/tree-child-sibling-notation/","title":"Tree Child-Sibling Notation","text":"

In this method, we change the structure of the tree. In a standard tree, each parent node is connected to all of its children. However, in the child-sibling notation, a node stores a pointer to only one of its children. Additionally, the node also stores a pointer to its immediate right sibling.

In this notation, every node has at most 2 children: - Left child (first child), - Right sibling (first sibling).

This structure is called the LCRS (Left Child-Right Sibling) notation. It effectively represents a binary tree, as every node has only two pointers (left and right).

a tree notated with child-sibling notation","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#why-you-would-use-the-lcrs-notation","title":"Why You Would Use the LCRS Notation","text":"

The primary reason for using LCRS notation is to save memory. In the LCRS structure, less memory is used compared to the standard tree notation.

","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#when-you-might-use-the-lcrs-notation","title":"When You Might Use the LCRS Notation:","text":"
  • Memory is extremely scarce.
  • Random access to a node\u2019s children is not required.
","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#possible-cases-for-using-lcrs","title":"Possible Cases for Using LCRS:","text":"
  1. When storing a large multi-way tree in main memory: For example, the phylogenetic tree.

  2. In specialized data structures where the tree is used in specific ways: For example, in the heap data structure, the main operations are:

  3. Removing the root of the tree and processing each of its children,

  4. Joining two trees together by making one tree a child of the other.

These operations can be done efficiently using the LCRS structure, making it convenient for working with heap data structures.

","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#references","title":"References","text":"
  • LCRS article on Wikipedia

  • Link to the Figure used

  • LCRS possible uses Stackoverflow

","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/walk-counting-with-matrix/","title":"Walk Counting using Matrix Exponentiation","text":"

Matrix exponentiation can be used to count the number of walks of a given length on a graph.

Let \\( l \\) be the desired walk length, and let \\( A \\) and \\( B \\) be nodes in a graph \\( G \\). If \\( D \\) is the adjacency matrix of \\( G \\), then \\( D^l[A][B] \\) represents the number of walks from node \\( A \\) to node \\( B \\) with length \\( l \\), where \\( D^k \\) denotes the \\( k \\)-th power of the matrix \\( D \\).

","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"dynamic-programming/walk-counting-with-matrix/#explanation","title":"Explanation:","text":"
  • Adjacency Matrix \\( D \\): In the adjacency matrix of a graph, each entry \\( D[i][j] \\) denotes whether there is a direct edge between node \\( i \\) and node \\( j \\). Specifically:
  • \\( D[i][j] = 1 \\) if there is an edge from \\( i \\) to \\( j \\),
  • \\( D[i][j] = 0 \\) otherwise.

  • Matrix Exponentiation: To find the number of walks of length \\( l \\) between nodes \\( A \\) and \\( B \\), we need to compute \\( D^l \\), which is the \\( l \\)-th power of the adjacency matrix \\( D \\). The entry \\( D^l[A][B] \\) will then give the number of walks of length \\( l \\) from node \\( A \\) to node \\( B \\).

graph LR\n    A(2) --> B(1);\n    B --> C(3);\n    C --> A;\n    C --> D(4);\n    D --> C;
D, adjacency matrix of G D^3, 3rd power of the matrix D

From the matrix \\( D^3 \\), we can see that there are 4 total walks of length 3.

Let \\( S \\) be the set of walks, and let \\( w \\) be a walk where \\( w = \\{n_1, n_2, ..., n_k\\} \\) and \\( n_i \\) is the \\( i \\)-th node of the walk. Then:

[ S = {{1, 3, 4, 3}, {3, 4, 3, 2}, {3, 4, 3, 4}, {4, 3, 4, 3}} ] and \\( |S| = 4 \\).

Using fast exponentiation on the adjacency matrix, we can efficiently find the number of walks of length \\( k \\) in \\( O(N^3 \\log k) \\) time, where \\( N \\) is the number of nodes in the graph.

","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"dynamic-programming/walk-counting-with-matrix/#time-complexity-breakdown","title":"Time Complexity Breakdown:","text":"
  • Matrix Multiplication: The \\( O(N^3) \\) time complexity comes from multiplying two \\( N \\times N \\) matrices.
  • Fast Exponentiation: Fast exponentiation reduces the number of multiplications to \\( \\log k \\), resulting in the overall time complexity of \\( O(N^3 \\log k) \\).

This method allows for efficiently calculating the number of walks with any length \\( k \\) in large graphs.

","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"dynamic-programming/walk-counting-with-matrix/#references","title":"References","text":"
  • Walk Counting on Sciencedirect
","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"graph/","title":"Graph","text":"

Editor: Kayacan Vesek

Reviewers: Yasin Kaya

"},{"location":"graph/#introduction","title":"Introduction","text":""},{"location":"graph/#definitions","title":"Definitions","text":""},{"location":"graph/#representing-graphs","title":"Representing Graphs","text":""},{"location":"graph/#tree-traversals","title":"Tree Traversals","text":""},{"location":"graph/#binary-search-tree","title":"Binary Search Tree","text":""},{"location":"graph/#heap","title":"Heap","text":""},{"location":"graph/#depth-first-search","title":"Depth First Search","text":""},{"location":"graph/#breadth-first-search","title":"Breadth First Search","text":""},{"location":"graph/#cycle-finding","title":"Cycle Finding","text":""},{"location":"graph/#bipartite-checking","title":"Bipartite Checking","text":""},{"location":"graph/#union-find","title":"Union Find","text":""},{"location":"graph/#shortest-path","title":"Shortest Path","text":""},{"location":"graph/#minimum-spanning-tree","title":"Minimum Spanning Tree","text":""},{"location":"graph/#topological-sort","title":"Topological Sort","text":""},{"location":"graph/#bridges-and-articulation-points","title":"Bridges and Articulation Points","text":""},{"location":"graph/#strong-connectivity-and-biconnectivity","title":"Strong Connectivity and Biconnectivity","text":""},{"location":"graph/#strongly-connected-components","title":"Strongly Connected Components","text":""},{"location":"graph/#max-flow","title":"Max Flow","text":""},{"location":"graph/#references","title":"References","text":"
  1. https://www.hackerearth.com/practice/algorithms/graphs/breadth-first-search/tutorial/
  2. https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/
  3. https://cp-algorithms.com/graph/depth-first-search.html
  4. https://www.hackerearth.com/practice/algorithms/graphs/depth-first-search/tutorial/
  5. Shortest Path. Wikipedia, the free online encyclopedia. Retrieved January 5, 2019
  6. Topological sort. Geeksforgeeks website. Retrieved January 5, 2019
  7. Topological Sort. Wikipedia, the free online encyclopedia. Retrieved January 5, 2019
  8. https://en.wikipedia.org/wiki/Graph_theory
"},{"location":"graph/binary-search-tree/","title":"Binary Search Tree","text":"

A Binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child.

For a binary tree to be a binary search tree, the values of all the nodes in the left sub-tree of the root node should be smaller than the root node's value. Also the values of all the nodes in the right sub-tree of the root node should be larger than the root node's value.

a simple binary search tree","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#insertion-algorithm","title":"Insertion Algorithm","text":"
  1. Compare values of the root node and the element to be inserted.
  2. If the value of the root node is larger, and if a left child exists, then repeat step 1 with root = current root's left child. Else, insert element as left child of current root.
  3. If the value of the root node is lesser, and if a right child exists, then repeat step 1 with root = current root's right child. Else, insert element as right child of current root.
","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#deletion-algorithm","title":"Deletion Algorithm","text":"
  • Deleting a node with no children: simply remove the node from the tree.
  • Deleting a node with one child: remove the node and replace it with its child.
  • Node to be deleted has two children: Find inorder successor of the node. Copy contents of the inorder successor to the node and delete the inorder successor.
  • Note that: inorder successor can be obtained by finding the minimum value in right child of the node.
","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#sample-code","title":"Sample Code","text":"
// C program to demonstrate delete operation in binary search tree \n#include<stdio.h>\n#include<stdlib.h>\n\nstruct node\n{\n    int key;\n    struct node *left, *right;\n};\n\n// A utility function to create a new BST node\nstruct node *newNode(int item)\n{\n    struct node *temp = (struct node *)malloc(sizeof(struct node));\n    temp->key = item;\n    temp->left = temp->right = NULL;\n    return temp;\n}\n\n// A utility function to do inorder traversal of BST\nvoid inorder(struct node *root)\n{\n    if (root != NULL)\n    {\n        inorder(root->left);\n        printf(\"%d \", root->key);\n        inorder(root->right);\n    }\n}\n\n/* A utility function to insert a new node with given key in BST */\nstruct node* insert(struct node* node, int key)\n{\n    /* If the tree is empty, return a new node */\n    if (node == NULL) return newNode(key);\n\n    /* Otherwise, recur down the tree */\n    if (key < node->key)\n        node->left = insert(node->left, key);\n    else\n        node->right = insert(node->right, key);\n\n    /* return the (unchanged) node pointer */\n    return node;\n}\n\n/* Given a non-empty binary search tree, return the node with minimum\n   key value found in that tree. Note that the entire tree does not\n   need to be searched. */\nstruct node * minValueNode(struct node* node)\n{\n    struct node* current = node;\n\n    /* loop down to find the leftmost leaf */\n    while (current->left != NULL)\n        current = current->left;\n\n    return current;\n}\n\n/* Given a binary search tree and a key, this function deletes the key\n   and returns the new root */\nstruct node* deleteNode(struct node* root, int key)\n{\n    // base case\n    if (root == NULL) return root;\n\n    // If the key to be deleted is smaller than the root's key,\n    // then it lies in left subtree\n    if (key < root->key)\n        root->left = deleteNode(root->left, key);\n\n    // If the key to be deleted is greater than the root's key,\n    // then it lies in right subtree\n    else if (key > root->key)\n        root->right = deleteNode(root->right, key);\n\n    // if key is same as root's key, then This is the node\n    // to be deleted\n    else\n    {\n        // node with only one child or no child\n        if (root->left == NULL)\n        {\n            struct node *temp = root->right;\n            free(root);\n            return temp;\n        }\n        else if (root->right == NULL)\n        {\n            struct node *temp = root->left;\n            free(root);\n            return temp;\n        }\n\n        // node with two children: Get the inorder successor (smallest\n        // in the right subtree)\n        struct node* temp = minValueNode(root->right);\n\n        // Copy the inorder successor's content to this node\n        root->key = temp->key;\n\n        // Delete the inorder successor\n        root->right = deleteNode(root->right, temp->key);\n    }\n    return root;\n}\n
","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#time-complexity","title":"Time Complexity","text":"

The worst case time complexity of search, insert, and deletion operations is \\(\\mathcal{O}(h)\\) where h is the height of Binary Search Tree. In the worst case, we may have to travel from root to the deepest leaf node. The height of a skewed tree may become \\(N\\) and the time complexity of search and insert operation may become \\(\\mathcal{O}(N)\\). So the time complexity of establishing \\(N\\) node unbalanced tree may become \\(\\mathcal{O}(N^2)\\) (for example the nodes are being inserted in a sorted way). But, with random input the expected time complexity is \\(\\mathcal{O}(NlogN)\\).

However, you can implement other data structures to establish Self-balancing binary search tree (which will be taught later), popular data structures that implementing this type of tree include:

  • 2-3 tree
  • AA tree
  • AVL tree
  • B-tree
  • Red-black tree
  • Scapegoat tree
  • Splay tree
  • Treap
  • Weight-balanced tree
","tags":["Tree","Binary Search","BST"]},{"location":"graph/bipartite-checking/","title":"Bipartite Checking","text":"

The question is in the title. Is the given graph bipartite? We can use BFS or DFS on graph. Lets first focus on BFS related algorithm. This procedure is very similar to BFS, we have an extra color array and we assign a color to each vertex when we are traversing the graph. Algorithm proof depends on fact that BFS explores the graph level by level. If the graph contains an odd cycle it means that there must be a edge between two vertices that are in same depth (layer, proof can be found on [1 - Algorithm Design, Kleinberg, Tardos]). Let's say the colors are red and black and we traverse the graph with BFS and assign red to odd layers and black to even layers. Then we check the edges to see if there exists an edge that its vertices are same color. If there is a such edge, the graph is not bipartite, else the graph is bipartite.

If two nodes x and y in the same layer are joined by an edge, then the cycle through x, y, and their lowest common ancestor z has odd length, demonstrating that the graph cannot be bipartite.
typedef vector<int> adjList;\ntypedef vector<adjList> graph;\ntypedef pair<int,int> ii;\nenum COLOR {RED, GREEN};\nbool bipartite_check(graph &g){\n    int root = 0; // Pick 0 indexed node as root.\n    vector<bool> visited(g.size(),false);\n    vector<int> Color(g.size(),0); \n    queue<ii> Q( { {root,0}} ); // insert root to queue, it is  first layer_0\n    visited[root] = true;\n    Color[root] = RED;\n    while ( !Q.empty() )\n    {\n        /*top.first is node, top.second its depth i.e layer */\n        auto top = Q.front();\n        Q.pop();\n        for (int u : g[top.first]){\n            if ( !visited[u] ){\n                visited[u] = true;\n                //Mark even layers to red, odd layers to green\n                Color[u] = (top.second+1) % 2 == 0 ?  RED : GREEN; \n                Q.push({u, top.second+1 });\n            }\n        }\n    }\n    for(int i=0; i < g.size(); ++i){\n        for( auto v: g[i]){\n            if ( Color[i] == Color[v] ) return false;\n        }\n    }\n    return true;\n}\nint main(){\n    graph g(3);\n    g[0].push_back(1);\n    g[1].push_back(2);\n    g[2].push_back(3);\n    cout << (bipartite_check(g) == true ? \"YES\" : \"NO\") << endl;\n    return 0;\n}\n

The complexity of algorithm is is $O(V + E) + O(E) $, BFS and loop over edges. But we can say it \\(O(V+E)\\) since it is Big-O notation.

","tags":["Bipartite Checking","Graph"]},{"location":"graph/breadth-first-search/","title":"Breadth First Search","text":"

Breadth First Search (BFS) is an algorithm for traversing or searching tree. (For example, you can find the shortest path from one node to another in an unweighted graph.)

An example breadth first search traversal","tags":["Graph","Breadth First Search","BFS"]},{"location":"graph/breadth-first-search/#method","title":"Method","text":"

BFS is a traversing algorithm where you should start traversing from a selected node (source or starting node) and traverse the graph layerwise thus exploring the neighbour nodes (nodes which are directly connected to source node). You must then move towards the next-level neighbour nodes. [1]

\u2022 As the name BFS suggests, you are required to traverse the graph breadthwise as follows: \u2022 First move horizontally and visit all the nodes of the current layer \u2022 Add to the queue neighbour nodes of current layer. \u2022 Move to the next layer, which are in the queue

Example question: Given a unweighted graph, a source and a destination, we need to find shortest path from source to destination in the graph in most optimal way?

#include <bits/stdc++.h>\nusing namespace std;\n\ncont int MaxN=100005; // Max number of nodes 5\n\nvector <int> adj[MaxN];\nbool mark[MaxN];\n\nvoid bfs(int starting_point,int ending_point) {\n    memset(mark,0,sizeof(mark)); //clear the cache\n    queue <pair <int,int> > q; // the value of node\n    // , and length between this node and the starting node\n\n    q.push_back(make_pair(starting_point,0));\n    mark[starting_point]=1;\n\n    while(q.empty()==false) {\n        pair <int,int> tmp = q.front(); // get the next node\n        q.pop(); // delete from q\n\n        if(ending_point==tmp.first) {\n            printf(\"The length of path between %d - %d : %d\\n\",\n            starting_point,ending_point,tmp.second);\n            return;\n        }\n\n        for (auto j : adj[tmp.first]) {\n            if(mark[j]) continue ; // if it reached before\n            mark[j]=1;\n            q.push_back(make_pair(j,tmp.second+1)); // add next node to queue\n        }\n    }\n}\n\nint main() {\n    cin \u00bb n\n\n    for (int i=0 ; i < m; i++) {\n        cin \u00bb a \u00bb b;\n        adj[a].push_back(b);\n    }\n\n    cin \u00bb start_point \u00bb end_point;\n    bfs(start_point);\n    return 0;\n}\n
","tags":["Graph","Breadth First Search","BFS"]},{"location":"graph/breadth-first-search/#complexity","title":"Complexity","text":"

The time complexity of BFS is \\(O(V + E)\\), where \\(V\\) is the number of nodes and \\(E\\) is the number of edges.

","tags":["Graph","Breadth First Search","BFS"]},{"location":"graph/bridges-and-articulation-points/","title":"Bridges and Articulation Points","text":"","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#dfs-order","title":"DFS Order","text":"

DFS order is traversing all the nodes of a given graph by fixing the root node in the same way as in the DFS algorithm, but without revisiting a discovered node. An important observation here is that the edges and nodes we use will form a tree structure. This is because, for every node (except the root), we only arrive from another node, and for the root node, we do not arrive from any other node, thus forming a tree structure.

void dfs(int node){\n    used[node] = true;\n    for(auto it : g[node])\n        if(!used[it])\n            dfs(it);\n}\n
","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#types-of-edges","title":"Types of Edges","text":"

When traversing a graph using DFS order, several types of edges can be encountered. These edges will be very helpful in understanding some graph algorithms.

Types of Edges: - Tree edge: These are the main edges used while traversing the graph. - Forward edge: These edges lead to a node that has been visited before and is located in our own subtree. - Back edge: These edges lead to nodes that have been visited before but where the DFS process is not yet complete. - Cross edge: These edges lead to nodes that have been visited before and where the DFS process is already complete.

An important observation about these edges is that in an undirected graph, it is impossible to have a cross edge. This is because it is not possible for an edge emerging from a node where the DFS process is complete to remain unvisited.

Green-colored edges are tree edges. Edge (1,8) is a forward edge. Edge (6,4) is a back edge. Edge (5,4) is a cross edge.","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#bridge","title":"Bridge","text":"

In an undirected and connected graph, if removing an edge causes the graph to become disconnected, this edge is called a bridge.

","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#finding-bridges","title":"Finding Bridges","text":"

Although there are several algorithms to find bridges (such as Chain Decomposition), we will focus on Tarjan's Algorithm, which is among the easiest to implement and the fastest.

When traversing a graph using DFS, if there is a back edge coming out of the subtree of the lower endpoint of an edge, then that edge is not a bridge. This is because the back edge prevents the separation of the subtree and its ancestors when the edge is removed.

This algorithm is based exactly on this principle, keeping track of the minimum depth reached by the back edges within the subtree of each node.

If the minimum depth reached by the back edges in the subtree of the lower endpoint of an edge is greater than or equal to the depth of the upper endpoint, then this edge is a bridge. This is because no back edge in the subtree of the edge's lower endpoint reaches a node above the current edge. Therefore, if we remove this edge, the subtree and its ancestors become disconnected.

Using Tarjan's Algorithm, we can find all bridges in a graph with a time complexity of \\(\\mathcal{O}(V + E)\\), where \\(V\\) represents the number of vertices and \\(E\\) represents the number of edges in the graph.

int dfs(int node, int parent, int depth) {\n    int minDepth = depth;\n    dep[node] = depth;  // dep dizisi her dugumun derinligini tutmaktadir.\n    used[node] = true;\n    for (auto it : g[node]) {\n        if (it == parent)\n            continue;\n        if (used[it]) {\n            minDepth = min(minDepth, dep[it]);\n            // Eger komsu dugum daha once kullanilmis ise\n            // Bu edge back edge veya forward edgedir.\n            continue;\n        }\n        int val = dfs(it, node, depth + 1);\n        // val degeri alt agacindan yukari cikan minimum derinliktir.\n        if (val >= depth + 1)\n            bridges.push_back({node, it});\n        minDepth = min(minDepth, val);\n    }\n    return minDepth;\n}\n
","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#articulation-point","title":"Articulation Point","text":"

In an undirected graph, if removing a node increases the number of connected components, that node is called an articulation point or cut point.

For example, if we remove node 0, the remaining nodes are split into two groups: 5 and 1, 2, 3, 4. Similarly, if we remove node 1, the nodes are split into 5, 0 and 2, 3, 4. Therefore, nodes 0 and 1 are **articulation points**.","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#finding-articulation-points","title":"Finding Articulation Points","text":"

Tarjan's Algorithm for finding articulation points in an undirected graph:

  • Traverse the graph using DFS order.

  • For each node, calculate the depth of the minimum depth node that can be reached from the current node and its subtree through back edges. This value is called the low value of the node.

  • If the low value of any child of a non-root node is greater than or equal to the depth of the current node, then the current node is an articulation point. This is because no back edge in the subtree of this node can reach a node above the current node. Therefore, if this node is removed, its subtree will become disconnected from its ancestors.

  • If the current node is the root (the starting node of the DFS order) and there are multiple branches during the DFS traversal, then the root itself is an articulation point. This is because the root has multiple connected subgraphs.

Using Tarjan's Algorithm, we can find all articulation points in a graph with a time complexity of \\(\\mathcal{O}(V + E)\\), where \\(V\\) is the number of vertices and \\(E\\) is the number of edges in the graph.

int dfs(int node, int parent, int depth) {\n    int minDepth = depth, children = 0;\n    dep[node] = depth;  // dep array holds depth of each node.\n    used[node] = true;\n    for (auto it : g[node]) {\n        if (it == parent)\n            continue;\n        if (used[it]) {\n            minDepth = min(minDepth, dep[it]);\n            continue;\n        }\n        int val = dfs(it, node, depth + 1);\n        if (val >= depth and parent != -1)\n            isCutPoint[node] = true;\n        minDepth = min(minDepth, val);\n        children++;\n    }\n    // This if represents the root condition that we mentioned above.\n    if (parent == -1 and children >= 2)\n        isCutPoint[node] = true;\n    return minDepth;\n}\n
","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/cycle-finding/","title":"Cycle Finding","text":"

Cycle: A sequence of nodes that returns to the starting node while visiting each node at most once and contains at least two nodes.

We can use dfs order in order to find the graph has a cycle or not.

If we find a back edge while traversing the graph then we can say that graph has a cycle. Because back edge connects the nodes at the top and bottom ends and causes a cycle.

The algorithm that we are going to use to find the cycle in the directed graph:

  • Traverse the graph with dfs order.
  • When you come to a node, color it gray and start visiting its neighbors.
  • If one of the current node's neighbors is gray, then there is a cycle in the graph. Because a gray node is definitely an ancestor of the current node, and an edge to one of its ancestors is definitely a back edge.
  • Once you're done visiting the neighbors, color the node black.
bool dfs(int node){\n    // The color array holds the color of each node.\n    // 0 represents white, 1 represents gray, and 2 represents black.\n    color[node] = 1;\n    for(int i = 0; i < g[node].size(); i++){\n        int child = g[node][i];\n        if(color[child] == 1)\n            return true;\n        if(!color[child])\n            if(dfs(child))\n                return true;\n    }\n    color[node] = 2;\n    return false;\n}\n
","tags":["Graph","Cycle"]},{"location":"graph/definitions/","title":"Graph Definitions","text":"","tags":["Graph"]},{"location":"graph/definitions/#definitions-of-common-terms","title":"Definitions of Common Terms","text":"
  • Node - An individual data element of a graph is called Node. Node is also known as vertex.
  • Edge - An edge is a connecting link between two nodes. It is represented as e = {a,b} Edge is also called Arc.
  • Adjacent - Two vertices are adjacent if they are connected by an edge.
  • Degree - a degree of a node is the number of edges incident to the node.
  • Undirected Graphs - Undirected graphs have edges that do not have a direction. The edges indicate a two-way relationship, in that each edge can be traversed in both directions.
  • Directed Graphs - Directed graphs have edges with direction. The edges indicate a one-way relationship, in that each edge can only be traversed in a single direction.
  • Weighted Edges - If each edge of graphs has an association with a real number, this is called its weight.
  • Self-Loop - It is an edge having the same node for both destination and source point.
  • Multi-Edge - Some Adjacent nodes may have more than one edge between each other.
","tags":["Graph"]},{"location":"graph/definitions/#walks-trails-paths-cycles-and-circuits","title":"Walks, Trails, Paths, Cycles and Circuits","text":"
  • Walk - A sequence of nodes and edges in a graph.
  • Trail - A walk without visiting the same edge.
  • Circuit - A trail that has the same node at the start and end.
  • Path - A walk without visiting same node.
  • Cycle - A circuit without visiting same node.
","tags":["Graph"]},{"location":"graph/definitions/#special-graphs","title":"Special Graphs","text":"
  • Complete Graph - A graph having at least one edge between every two nodes.
  • Connected Graph - A graph with paths between every pair of nodes.
  • Tree - an undirected connected graph that has any two nodes that are connected by exactly one path. There are some other definitions that you can notice it is tree:
    • an undirected graph is connected and has no cycles. an undirected graph is acyclic, and a simple cycle is formed if any edge is added to the graph.
    • an undirected graph is connected, it will become disconnected if any edge is removed.
    • an undirected graph is connected, and has (number of nodes - 1) edges.
","tags":["Graph"]},{"location":"graph/definitions/#bipartite-graphs","title":"Bipartite Graphs","text":"

A bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets U and V such that every edge connects a vertex in U to one in V. Vertex sets U and V are usually called the parts of the graph. [1]. The figure is shown in below. It is similar to graph coloring with two colors. Coloring graph with two colors is that every vertex have a corresponding color, and for any edge, it's vertices should be different color. In other words, if we can color neighbours two different colors, we can say that graph is bipartite.

Example bipartite graph, all edges satisfy the coloring constraint

We have some observations here. - A graph 2- colorable if and only if it is bipartite. - A graph does not contain odd-length cycle if and only if it is bipartite. - Every tree is a bipartite graph since trees do not contain any cycles.

","tags":["Graph"]},{"location":"graph/definitions/#directed-acyclic-graphs","title":"Directed Acyclic Graphs","text":"

A directed acyclic graph(DAG) is a finite directed graph with no directed cycles. Equivalently, a DAG is a directed graph that has a topological ordering (we cover it in this bundle), a sequence of the vertices such that every edge is directed from earlier to later in the sequence [2]. DAGs can be used to encode precedence relations or dependencies in a natural way [3 - Algorithm Design, Kleinberg, Tardos]. There are several applications using topological ordering directly such as finding critical path or automatic differentiation on computational graphs (this is extremely useful for deep learning frameworks [4]).

Example Directed Acyclic Graphs Example computational graph also a DAG, partial derivatives are written to edges respect to topological order","tags":["Graph"]},{"location":"graph/depth-first-search/","title":"Depth First Search","text":"

Depth First Search (DFS) is an algorithm for traversing or searching tree. (For example, you can check if graph is connected or not via DFS) [2]

Example of DFS traversal","tags":["Graph","Depth First Search","DFS"]},{"location":"graph/depth-first-search/#method","title":"Method","text":"

The DFS algorithm is a recursive algorithm that uses the idea of backtracking. It involves exhaustive searches of all the nodes by going ahead, if possible, else by backtracking.

Here, the word backtrack means that when you are moving forward and there are no more nodes along the current path, you move backwards on the same path to find nodes to traverse. All the nodes will be visited on the current path till all the unvisited nodes have been traversed after which the next path will be selected. [3]

vector<vector<int\u00bb adj; // graph represented as an adjacency list\nint n; // number of vertices\nvector<bool> visited;\nvoid dfs(int v) {\n    visited[v] = true;\n    for (int u : adj[v]) {\n        if (!visited[u]) dfs(u);\n    }\n}\n

This recursive nature of DFS can be implemented using stacks. The basic idea is as follows: Pick a starting node and push all its adjacent nodes into a stack. Pop a node from stack to select the next node to visit and push all its adjacent nodes into a stack. Repeat this process until the stack is empty. However, ensure that the nodes that are visited are marked. This will prevent you from visiting the same node more than once. If you do not mark the nodes that are visited and you visit the same node more than once, you may end up in an infinite loop. [3]

DFS-iterative(G, s): //Where G is graph and s is source vertex let S be stack\nS.push(s) //Inserting s in stack\nmark s as visited.\nwhile ( S is not empty):\n    //Pop a vertex from stack to visit next v = S.top( )\n    S.pop( )\n    //Push all the neighbours of v in stack that are not visited\n    for all neighbours w of v in Graph G:\n        if w is not visited :\n            S.push(w)\n            mark w as visited\n

Example Question: Given an undirected graph, find out whether the graph is strongly connected or not? An undirected graph is strongly connected if there is a path between any two pair of vertices.

#include <bits/stdc++.h>\nusing namespace std;\n\ncont int MaxN=100005; // Max number of nodes\n\nvector <int> adj[MaxN];\nbool mark[MaxN];\n\nvoid dfs(int k) {\n    mark[k]=1; // visited\n    for(auto j : adj[k]) // iterate over adjacent nodes\n        if(mark[j]==false) // check if it is visited or not\n            dfs(j); // do these operation for that node\n}\n\nint main() {\n    cin \u00bb n \u00bb m; // number of nodes , number of edges\n    for (int i=0 ; i < m; i++){\n        cin \u00bb a \u00bb b;\n        adj[a].push_back(b);\n        adj[b].push_back(a);\n    }\n\n    dfs(1);\n\n    bool connected=1;\n    for(int i=1 ; i <= n ;i++)\n        if(mark[i]==0) {\n            connected=0;\n            break;\n        }\n\n    if(connected)\n        cout \u00ab \"Graph is connected\" \u00ab endl;\n    else\n        cout \u00ab \"Graph is not connected\" \u00ab endl;\n\n    return 0;\n}\n
","tags":["Graph","Depth First Search","DFS"]},{"location":"graph/depth-first-search/#complexity","title":"Complexity","text":"

The time complexity of DFS is \\(O(V+E)\\) when implemented using an adjacency list ( with Adjacency Matrices it is \\(O(V^2)\\)), where \\(V\\) is the number of nodes and \\(E\\) is the number of edges. [4]

","tags":["Graph","Depth First Search","DFS"]},{"location":"graph/heap/","title":"Heap","text":"an example max-heap with 9 nodes

The heap is a complete binary tree with N nodes, the value of all the nodes in the left and right sub-tree of the root node should be smaller than the root node's value.

In a heap, the highest (or lowest) priority element is always stored at the root. A heap is not a sorted structure and can be regarded as partially ordered. As visible from the heap-diagram, there is no particular relationship among nodes on any given level, even among the siblings. Because a heap is a complete binary tree, it has a smallest possible height. A heap with \\(N\\) nodes has \\(logN\\) height. A heap is a useful data structure when you need to remove the object with the highest (or lowest) priority.

","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#implementation","title":"Implementation","text":"

Heaps are usually implemented in an array (fixed size or dynamic array), and do not require pointers between elements. After an element is inserted into or deleted from a heap, the heap property may be violated and the heap must be balanced by internal operations.

The first (or last) element will contain the root. The next two elements of the array contain its children. The next four contain the four children of the two child nodes, etc. Thus the children of the node at position n would be at positions \\(2*n\\) and \\(2*n + 1\\) in a one-based array. This allows moving up or down the tree by doing simple index computations. Balancing a heap is done by sift-up or sift-down operations (swapping elements which are out of order). So we can build a heap from an array without requiring extra memory.

example a heap as an array","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#insertion","title":"Insertion","text":"

Basically add the new element at the end of the heap. Then look it's parent if it is smaller or bigger depends on the whether it is max-heap or min-heap (max-heap called when Parents are always greater), swap with the parent. If it is swapped do the same operation for the parent.

","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#deletion","title":"Deletion","text":"

If you are going to delete a node (root node or another one does not matter),

  1. Swap the node to be deleted with the last element of heap to maintain a balanced structure.
  2. Delete the last element which is the node we want to delete at the start.
  3. Now you have a node which is in the wrong place, You have to find the correct place for the swapped last element, to do this starting point you should check its left and right children, if one them is greater than our node you should swap it with the greatest child(or smallest if it is min-heap).
  4. Still current node may in the wrong place, so apply Step 3 as long as it is not greater than its children(or smaller if it is min-heap).
an example deletion on a heap structure
class BinHeap:\n    def __init__(self):\n        self.heapList = [0]\n        self.currentSize = 0\n\n    def percUp(self,i):\n        while i // 2 > 0:\n            if self.heapList[i] < self.heapList[i // 2]:\n                tmp = self.heapList[i // 2]\n                self.heapList[i // 2] = self.heapList[i]\n                self.heapList[i] = tmp\n            i = i // 2\n\n    def insert(self,k):\n        self.heapList.append(k)\n        self.currentSize = self.currentSize + 1\n        self.percUp(self.currentSize)\n\n    def percDown(self,i):\n        while (i * 2) <= self.currentSize:\n            mc = self.minChild(i)\n            if self.heapList[i] > self.heapList[mc]:\n                tmp = self.heapList[i]\n                self.heapList[i] = self.heapList[mc]\n                self.heapList[mc] = tmp\n            i = mc\n\n    def minChild(self,i):\n        if i * 2 + 1 > self.currentSize:\n            return i * 2\n        else:\n            if self.heapList[i*2] < self.heapList[i*2+1]:\n                return i * 2\n            else:\n                return i * 2 + 1\n\n    def delMin(self):\n        retval = self.heapList[1]\n        self.heapList[1] = self.heapList[self.currentSize]\n        self.currentSize = self.currentSize - 1\n        self.heapList.pop()\n        self.percDown(1)\n        return retval\n\n    def buildHeap(self,alist):\n        i = len(alist) // 2\n        self.currentSize = len(alist)\n        self.heapList = [0] + alist[:]\n        while (i > 0):\n            self.percDown(i)\n            i = i - 1\n\nbh = BinHeap()\nbh.buildHeap([9,5,6,2,3])\n\nprint(bh.delMin())\nprint(bh.delMin())\nprint(bh.delMin())\nprint(bh.delMin())\nprint(bh.delMin())\n
","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#complexity","title":"Complexity","text":"

Insertion \\(\\mathcal{O}(logN)\\), delete-min \\(\\mathcal{O}(logN)\\) , and finding minimum \\(\\mathcal{O}(1)\\). These operations depend on heap's height and heaps are always complete binary trees, basically the height is \\(logN\\). (N is number of Node)

","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#priority-queue","title":"Priority Queue","text":"

Priority queues are a type of container adaptors, specifically designed so that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.

While priority queues are often implemented with heaps, they are conceptually distinct from heaps. A priority queue is an abstract concept like \"a list\" or \"a map\"; just as a list can be implemented with a linked list or an array, a priority queue can be implemented with a heap or a variety of other methods such as an unordered array.

#include <iostream>       // std::cout\n#include <queue>          // std::priority_queue\nusing namespace std;\nint main () {\n    priority_queue<int> mypq;\n\n    mypq.push(30);\n    mypq.push(100);\n    mypq.push(25);\n    mypq.push(40);\n\n    cout << \"Popping out elements...\";\n    while (!mypq.empty()) {\n        cout << ' ' << mypq.top();\n        mypq.pop();\n    }\n    return 0;\n}\n
","tags":["Heap","Priority Queue"]},{"location":"graph/introduction/","title":"Introduction","text":"

A graph is a structure amounting to a set of objects in which some pairs of the objects are in some sense \"related\". The objects correspond to the mathematical abstractions called vertices (also called nodes or points) and each of the related pairs of vertices is called an edge. Typically, a graph is depicted in diagrammatic form as a set of dots for the vertices, joined by lines for the edges. [8]

Why graphs? Graphs are usually used to represent different elements that are somehow related to each other.

A Graph consists of a finite set of vertices(or nodes) and set of edges which connect a pair of nodes. G = (V,E)

V = set of nodes

E = set of edges(e) represented as e = a,b

Graph are used to show a relation between objects. So, some graphs may have directional edges (e.g. people and their love relationships that are not mutual: Alice may love Alex, while Alex is not in love with her and so on), and some graphs may have weighted edges (e.g. people and their relationship in the instance of a debt)

Figure 1: a simple unweigted graph","tags":["Graph"]},{"location":"graph/max-flow/","title":"Max Flow","text":"","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/max-flow/#flow-network","title":"Flow Network","text":"

A flow network is a special type of directed graph that contains a single source and a single target node. In a flow network, each edge has a capacity, which indicates the maximum amount of flow that can pass through that edge.

One of the earliest examples of a flow network in history.","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/max-flow/#maximum-flow","title":"Maximum Flow","text":"

Maximum flow is an algorithm that calculates the maximum amount of flow that can reach the target from the source in a flow network while maintaining a continuous flow.

There are several algorithms to solve the Maximum Flow problem. The time complexities of some popular ones are:

  • Ford-Fulkerson algorithm: \\(\\mathcal{O}(E * \\text{flowCount})\\)
  • Edmonds-Karp algorithm: \\(\\mathcal{O}(V * E^2)\\)
  • Dinic's algorithm: \\(\\mathcal{O}(E * V^2)\\)

Where V is the number of vertices and E is the number of edges in the flow network.

","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/max-flow/#ford-fulkerson","title":"Ford Fulkerson","text":"

The steps of the Ford-Fulkerson maximum flow algorithm are as follows:

  • Find a path from the source to the target.
  • The edge with the minimum capacity in the found path determines the flow that can pass through this path.
  • Decrease the capacities of the edges in the path by the flow amount (the minimum capacity found in step 2) and add the reverse edges to the graph with a capacity equal to the flow.
  • Repeat until there are no more paths from the source to the target.

Why does this algorithm work?

For example, let's assume we find a flow of size x through an edge from u to v.

Suppose the path we found is \\(a \\rightarrow ... \\rightarrow u \\rightarrow v \\rightarrow ... \\rightarrow b\\).

We will add a new edge from v to u with a capacity of x to our graph, but this newly added reverse edge does not exist in the original graph.

After adding the reverse edges, the new path we find might look like \\(c \\rightarrow ... \\rightarrow v \\rightarrow u \\rightarrow ... \\rightarrow d\\), with a flow of size y.

It is clear that \\(y \\leq x\\).

We can represent three different valid flows as follows:

  • A flow of size y following the path \\(a \\rightarrow ... \\rightarrow u \\rightarrow ... \\rightarrow d\\)
  • A flow of size y following the path \\(c \\rightarrow ... \\rightarrow u \\rightarrow ... \\rightarrow b\\)
  • A flow of size x - y following the path \\(a \\rightarrow ... \\rightarrow u \\rightarrow v \\rightarrow ... \\rightarrow d\\)

The overall time complexity of the Ford-Fulkerson algorithm is \\(\\mathcal{O}(E * \\text{flowCount})\\) because, in the worst case, each found path increases the flow by only 1. Since finding each path takes time proportional to the number of edges, the complexity becomes \\(\\mathcal{O}(E * \\text{flowCount})\\).

However, if we implement the Ford-Fulkerson algorithm using BFS, the complexity changes. In this case, for every edge, the flows that consider this edge as the bottleneck will continually increase, leading to a time complexity of \\(\\mathcal{O}(V * E^2)\\). This specific implementation is known as the Edmonds-Karp Algorithm.

The figure on the left shows how much flow is passing through each edge. The figure on the right represents the current state of the graph. Flow = 7 Flow = 8 Flow = 13 Flow = 15
// c matrix holds the capacities of the edges.\n// g adjacency list allows us to traverse the graph.\nbool bfs() {\n    vector<bool> visited(n, false);\n    queue<int> q;\n    q.push(source);\n    visited[source] = true;\n    while (!q.empty()) {\n        int node = q.front();\n        q.pop();\n        if (node == sink)\n            break;\n        for (int i = 0; i < g[node].size(); i++) {\n            int child = g[node][i];\n            if (c[node][child] <= 0 or visited[child])\n                continue;\n            visited[child] = true;\n            parent[child] = node;\n            q.push(child);\n        }\n    }\n    return visited[sink];\n}\nint max_flow() {\n    while (bfs()) {\n        int curFlow = -1, node = sink;\n        while (node != source) {\n            // curFlow is the minimum capacity in the current path, i.e. the flow we found.\n            int len = c[parent[node]][node];\n            if (curFlow == -1)\n                curFlow = len;\n            else\n                curFlow = min(curFlow, len);\n            node = parent[node];\n        }\n        flow += curFlow;\n        node = sink;\n        while (node != source) {\n            c[parent[node]][node] -= curFlow;\n            // We are subtracting the flow we found from the path we found.\n            c[node][parent[node]] += curFlow;  // We are adding the reverses of the edges\n            node = parent[node];\n        }\n    }\n    return flow;\n}\n
","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/minimum-spanning-tree/","title":"Minimum Spanning Tree","text":"","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/minimum-spanning-tree/#definition","title":"Definition","text":"

Given an undirected weighted connected graph \\(G = (V,E)\\) Spanning tree of G is a connected acyclic sub graph that covers all nodes and some edges. In a disconnected graph -where there is more than one connected component- the spanning tree of that graph is defined as the forest of the spanning trees of each connected component of the graph.

Minimum spanning tree (MST) is a spanning tree in which the sum of edge weights is minimum. The MST of a graph is not unique in general, there might be more than one spanning tree with the same minimum cost. For example, take a graph where all edges have the same weight, then any spanning tree would be a minimum spanning tree. In problems involving minimum spanning trees where you have to output the tree itself (and not just the minimum cost), it either puts more constraint so the answer is unique, or simply asks for any minimum spanning tree.

MST of the graph. It spans all nodes of the graph and it is connected.

To find the minimum spanning tree of a graph, we will introduce two algorithms. The first one called Prim's algorithm, which is similar to Dijkstra's algorithm. Another algorithm is Kruskal agorithm, which makes use of the disjoint set data structure. Let's discover each one of them in detail!

","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/minimum-spanning-tree/#prim-algorithm","title":"Prim Algorithm","text":"

Prim algorithm is very similar to Dijkstra's shortest path algorithm. In this algorithm we have a set \\(S\\) which represents the explored nodes and again we can maintain a priority queue data structure the closest node in \\(V-S\\). It is a greedy algorithm just like Dijkstra's shortest path algorithm.

G = (V, E)   V set of all nodes, E set of all edges\nT = {}       result, edges of MST\nS = {1}      explored nodes\nwhile S /= V do\n    let (u, v) be the lowest cost edge such that u in S and v in V - S;\n    T = T U {(u, v)}\n    S = S U {v}\nend\n
Prim Algorithm in Pseudo code, what is the problem here?

There is a problem with this implementation, it assumes that the graph is connected. If the graph is not connected this algorithm will be stuck on loop. There is a good visualization for Prim algorithm at [10]. If we use priority queue complexity would be \\(O(ElogV)\\).

Example of how Prim Algorithm constructs the MST","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/minimum-spanning-tree/#kruskal-algorithm","title":"Kruskal Algorithm","text":"

In Prim algorithm we started with a specific node and then proceeded with choosing the closest neighbor node to our current graph. In Kruskal algorithm, we follow a different strategy; we start building our MST by choosing one edge at a time, and link our (intially separated) nodes together until we connect all of the graph.

To achieve this task, we will start with having all the nodes separated each in a group. In addition, we will have the list of edges from the original graph sorted based on their cost. At each step, we will:

  1. Pick the smallest available edge (that is not taken yet)
  2. Link the nodes it connects together, by merging their group into one unified group
  3. Add the cost of the edge to our answer

However, you may realize in some cases the link we add will connect two nodes from the same group (because they were grouped before by other taken edges), hence violating the spanning tree condition (Acyclic) and more importantly introducing unnecessary edges that adds more cost to the answer. So to solve this problem, we will only add the edges as long as they connect two currently (at the time of processing this edge) separated nodes that belong to different groups, hence completing the algorithm.

The optimality of Kruskal algorithm comes from the fact that we are taking from a sorted list of edges. For more rigorous proof please refer to [11].

So how can we effectively merge the group of nodes and check that which group each node belong? We can utilize disjoint set data structure which will help us to make union and find operations in an amortized constant \\(\\mathcal{O}(1)\\) time.

typedef pair<int,pair<int,int>> edge;\n// represent edge as triplet (w,u,v)\n// w is weigth, u and v verticies.\n// edge.first is weigth edge.second.first -> u, edge.second.second -> v\ntypedef vector<edge> weigthed_graph;\n\n/*union - find data structure utilities */\nconst int maxN = 3005;\nint parent[maxN];\nint ssize[maxN];\nvoid make_set(int v);\nint find_set(int v);\nvoid union_sets(int a, int b);\nvoid init_union_find();\n\n/*Code that finds edges in MST */\nvoid kruskal(vector<edge> &edgeList ){\n    vector<edge> mst;\n    init_union_find();\n    sort(edgeList.begin(),edgeList.end(), \\\n        [](const auto &a, const auto  &b) { return a.first< b.first;}); \n    //well this weird syntax is lambda function \n    // for sorting pairs to respect their first element.\n    for( auto e: edgeList){\n        if( find_set(e.second.first )!= find_set(e.second.second)){\n            mst.push_back(e);\n            union_sets(e.second.first, e.second.second);\n        }\n    }\n}\n

To calculate the time complexity, observe how we first sorted the edges, this takes \\(\\mathcal{O}(E log E)\\). In addition we pass through the edges one by one, and each time we check which group the two nodes of the edge belongs to, and in some cases merge the two groups. So in the worst case we will assume that both operations (finding and merging) happens, but since the disjoint data structure guarantee \\(\\mathcal{O}(1)\\) amortized time for both operations, we end up with \\(\\mathcal{O}(E)\\) amortized time of processing the nodes.

So in total we have \\(\\mathcal{O}(E log E)\\) from sorting edges and \\(\\mathcal{O}(E)\\) from processing them, those results in a total of \\(\\mathcal{O}(E log E)\\) (if you don't understand why please refer to the first bundle where we discuss time complexity).

Example of how Kruskal Algorithm constructs the MST","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/representing-graphs/","title":"Representing Graphs","text":"","tags":["Graph"]},{"location":"graph/representing-graphs/#edge-lists","title":"Edge Lists","text":"

A simple way to define edge list is that it has a list of pairs. We just have a list of objects consisting of the vertex numbers of 2 nodes and other attributes like weight or the direction of edges. [16]

  • + For some specific algorithms you need to iterate over all the edges, (i.e. kruskal's algorithm)
  • + All edges are stored exactly once.
  • - It is hard to determine whether two nodes are connected or not.
  • - It is hard to get information about the edges of a specific vertex.
#include <iostream>\n#include <vector>\nusing namespace std;\n\nint main(){\n    int edge_number;\n    vector<pair <int,int> > edges;\n    cin >> edge_number;\n    for( int i=0 ; i<edge_number ; i++ ){\n        int a,b;\n        cin >> a >> b;\n        edges.push_back(make_pair(a,b)); // a struct can be used if edges are weighted or have other properties.\n    }\n}\n
","tags":["Graph"]},{"location":"graph/representing-graphs/#adjacency-matrices","title":"Adjacency Matrices","text":"

Stores edges, in a 2-D matrix. matrix[a][b] keeps an information about road from a to b. [16] - + We can easily check if there is a road between two vertices. - - Looping through all edges of a specific node is expensive because you have to check all of the empty cells too. Also these empty cells takes huge memory in a graph which has many vertices. (For example representing a tree)

#include <iostream>\n#include <vector>\nusing namespace std;\nint main(){\n    int node_number;\n    vector<vector<int> > Matrix;\n    cin >> node_number;\n    for( int i=0 ; i<node_number ; i++ )\n        for( int j=0 ; j<node_number ; j++ ){\n            Matrix.push_back(vector <int> ());\n            int weight;\n            cin >>weight ;\n            Matrix[i].push_back(weight);\n        }\n}\n
","tags":["Graph"]},{"location":"graph/representing-graphs/#adjacency-list","title":"Adjacency List","text":"

Each node has a list consisting of nodes each is adjacent to. So, there will be no empty cells. Memory will be equal to number of edges. The most used one is in algorithms. [16]

  • + You do not have to use space for empty cells.
  • + Easily iterate over all the neighbors of a specific node.
  • - If you want to check if two nodes are connected, in this form you still need to iterate over all the neighbors of one of them. But, there are some structures that you can do this operation in O(log N). For example if you won't add any edge, you can sort every vector with nodes' names, so you can find it by binary search.
#include <iostream>\n#include <vector>\nusing namespace std;\n\nint main(){\n    int node_number,path_number;\n\n    vector<vector<int> > paths; \n    // use object instead of int, \n    //if you need to store other features\n\n    cin >> node_number >> path_number;\n    for( int i=0 ; i<node_number ; i++ )\n        Matrix.push_back(vector <int> ());\n    for( int j=0 ; j< path_number ; j++ ){\n        int beginning_node, end_node;\n        cin >> beginning_node >> end_node;\n\n        Matrix[ beginning_node ].push_back( end_node ); // push st\n        // Matrix[ end_node ].push_back(  beginning_node ); \n        // ^^^ If edges are Undirected, you should push in reverse direction too\n    }\n}\n
","tags":["Graph"]},{"location":"graph/shortest-path/","title":"Shortest Path Problem","text":"","tags":["Graph","Shortest Path Problem","Dijkstra"]},{"location":"graph/shortest-path/#definition","title":"Definition","text":"

Let \\(G(V,E)\\) be a graph, \\(v_i\\) and \\(v_j\\) be two nodes of \\(G\\). We say a path between \\(v_i\\) and \\(v_j\\) is the shortest path if sum of the edge weights (cost) in the path is minimum. In other words, the shortest path problem is the problem of finding a path between two vertices (or nodes) in a graph such that the sum of the weights of its constituent edges is minimized. [5]

Example shortest path in graph. Source is A and target is F. Image taken from [5].

We will cover several shortest path algorithms in this bundle. One of them is Dijkstra\u2019s Shortest Path Algorithm but it has some drawbacks: Edge weights should be non-negative for the optimally of the algorithm. We will discover other algorithms in which these condition isn\u2019t necessary, like Floyd-Warshall and Bellman-Ford algorithms.

","tags":["Graph","Shortest Path Problem","Dijkstra"]},{"location":"graph/shortest-path/#dijkstras-shortest-path-algorithm","title":"Dijkstra's Shortest Path Algorithm","text":"

Dijkstra\u2019s Shortest Path algorithm is straight forward. In brief we have a set \\(S\\) that contains explored nodes and \\(d\\) which contains the shortest path cost from source to another node. In other words, \\(d(u)\\) represents the shortest path cost from source to node \\(u\\). The procedure follows as that. First, add source node to set \\(S\\) which represents the explored nodes and assigns the minimum cost of the source to zero. Then each iteration we add node to \\(S\\) that has lowest cost \\((d(u))\\) from unexplored nodes. Let\u2019s say \\(S\u2032 = V \u2212 S\\) which means unexplored nodes. For all nodes in \\(S\u2032\\) we calculate \\(d(x)\\) for each node \\(x\\) is \\(S\u2032\\) then we pick minimum cost node and add it to \\(S\\). So how we calculate \\(d(x)\\)? For any \\(x\\) node from \\(S\u2032\\), \\(d(x)\\) calculated as that, let\u2019s say \\(e\\) cost of any edge from \\(S\\) to \\(x\\) then \\(d(x) = min(d(u) + e)\\). It is a greedy algorithm.

Here is the explanation of the algorithm step by step.

  1. Initialize an empty set, distance array, insert source to set.

  2. Initialize a min-heap, put source to heap with key is zero.

  3. While heap is not empty, take the top element from heap and add its neighbours to min-heap.

  4. Once we pick an element from the heap, it is guaranteed that the same node will never be added to heap with lower key value.

In implementation we can use priority queue data structure in order to increase efficiency. If we put unexplored nodes to min - priority queue where the distance is key, we can take the lowest cost unexplored node in \\(O(log(n))\\) time which is efficient.

typedef pair<int,int> edge;\ntypedef vector<edge> adjList;\ntypedef vector<adjList> graph;\n\nvoid dijkstra(graph &g, int s) {\n    vector<int> dist(g.size(),INT_MAX/2);\n    vector<bool> visited(g.size(),false);\n\n    dist[s] = 0;\n\n    priority_queue<edge, vector<edge>, greater<edge>> q;\n    q.push({0, s});\n\n    while(!q.empty()) {\n        int v = q.top().second;\n        int d = q.top().first;\n        q.pop();\n\n        if(visited[v]) continue;\n        visited[v] = true;\n\n        for(auto it: g[v]) {\n            int u = it.first;\n            int w = it.second;\n            if(dist[v] + w < dist[u]) {\n                dist[u] = dist[v] + w;\n                q.push({dist[u], u});\n            } \n        }       \n    }\n}\n
","tags":["Graph","Shortest Path Problem","Dijkstra"]},{"location":"graph/strong-connectivity-and-biconnectivity/","title":"Strong Connectivity and Biconnectivity","text":"","tags":["Strong Connectivity","Biconnectivity","Graph"]},{"location":"graph/strong-connectivity-and-biconnectivity/#strong-connectivity","title":"Strong Connectivity","text":"

To reach a target node from a given node, it must be possible to arrive at the target by passing through a finite number of nodes.

In an undirected graph, if every node is reachable from every other node, the graph is called connected. When the same concept is applied to directed graphs, it is called strongly connected.

In other words, for a directed graph to be strongly connected, it must be possible to reach every other node from any given node.

","tags":["Strong Connectivity","Biconnectivity","Graph"]},{"location":"graph/strong-connectivity-and-biconnectivity/#biconnectivity","title":"Biconnectivity","text":"

In an undirected graph, if the remaining graph remains connected when any node is removed, the graph is called biconnected. In other words, if the graph has no articulation points, it is considered a biconnected graph.

An example of biconnected graph","tags":["Strong Connectivity","Biconnectivity","Graph"]},{"location":"graph/strongly-connected-components/","title":"Strongly Connected Components","text":"

All directed graphs can be divided into disjoint subgraphs that are strongly connected. For two subgraphs to be disjoint, they must not share any common edges or nodes. If we consider each of these resulting subgraphs as a single node and create a new graph, the resulting graph will be a directed acyclic graph (DAG), meaning it will have no cycles.

The subgraphs marked in red are the strongly connected components. The newly formed graph, created by treating each strongly connected component as a single node, results in a directed acyclic graph (DAG), meaning it contains no cycles.

Tarjan's Algorithm for finding strongly connected components (SCCs) in a directed graph (An alternative approach is Kosaraju's Algorithm, but Tarjan's algorithm is often preferred in practice due to its speed and simpler understanding):

  • Start traversing the graph using DFS order from any node and push the visited nodes onto a stack. Calculate the discovery time for each node. (Discovery time is the time unit when the node is first reached during DFS traversal, and we will call this the index.)
  • If a node is in the stack, it is not yet part of any strongly connected component. This is because, when a strongly connected component is found, all the nodes belonging to that component are removed from the stack.
  • For each node, calculate the index of the node that has the minimum index among the nodes reachable from the current node and its subtree through edges that do not belong to any strongly connected component. This value is called the \"minimum reachable depth\" from the subtree of the node (also known as the \"low\" value).
  • If a node's low value is equal to its own index, then this node and all nodes below it in the stack form a strongly connected component. This is because if we call this node \"u,\" there must be an edge from u's subtree back to u itself. Otherwise, u's low value would be clearly smaller than its own index.
  • When a strongly connected component is found (as explained in the previous step), remove all nodes belonging to this component from the stack.

Using Tarjan's Algorithm, we can find all strongly connected components in a graph with a time complexity of \\(\\mathcal{O}(V + E)\\), where \\(V\\) is the number of vertices and \\(E\\) is the number of edges.

void dfs(int node) {\n    low[node] = index[node] = ++curTime;\n    // curTime holds the discovery time of each node.\n    used[node] = true;\n\n    st.push(node);\n    inStack[node] = true;\n    // inStack holds whether a node is in the stack or not.\n    for (auto it : g[node]) {\n        if (!used[it]) {\n            dfs(it);\n            low[node] = min(low[node], low[it]);\n        } else if (inStack[it])\n            low[node] = min(low[node], index[it]);\n        // If the adjacent node is in the stack, then this edge can be a back edge.\n    }\n    if (low[node] == index[node]) {\n        while (1) {\n            int x = st.top();\n            st.pop();\n            cout << x << \" \";\n            inStack[x] = false;\n            if (x == node)\n                break;\n        }\n        cout << endl;\n    }\n}\n\nvoid scc() {\n    for (int i = 0; i < n; i++)\n        if (!used[i])\n            dfs(i);\n}\n
","tags":["Strongly Connected Components","Graph"]},{"location":"graph/topological-sort/","title":"Topological Sort","text":"","tags":["Graph","Topological Sort"]},{"location":"graph/topological-sort/#definition","title":"Definition","text":"

Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u->v, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG [6].

There are many important usages of topological sorting in computer science; applications of this type arise in instruction scheduling, ordering of formula cell evaluation when recomputing formula values in spreadsheets, logic synthesis, determining the order of compilation tasks to perform in makefiles, data serialization, and resolving symbol dependencies in linkers. It is also used to decide in which order to load tables with foreign keys in databases [7].

There are known algorithms (e.g Kahn\u2019s algorithm) to find topological order in linear time. Below, you can find one of the implementations:

For example, a topological sorting of this graph is \u201c5 4 2 3 1 0\u201d. There can be more than one topological sorting for a graph. For example, another topological sorting of the following graph is \u201c4 5 2 3 1 0\u201d. The first vertex in topological sorting is always a vertex with in-degree as 0 (a vertex with no incoming edges)[6].","tags":["Graph","Topological Sort"]},{"location":"graph/topological-sort/#algorithm","title":"Algorithm","text":"
typedef vector<int> adjList;\ntypedef vector<adjList> graph;\ntypedef pair<int,int> ii;\n\nvoid kahn(graph &g) {\n    vector<int> result;\n    queue<int> q;\n    vector<int> degree(g.size(),0); // number of incoming egdes.\n    for(auto &list: g){\n        for(auto &node:list) {\n            degree[node]++;\n        } \n    }\n\n    for(int i=0; i < g.size(); ++i) {\n        if (degree[i] == 0)\n        q.push(i);\n    }\n\n    while( !q.empty()) {\n        int node = q.front();\n        result.push_back(node);\n        q.pop();\n\n        for (auto &ng: g[node]) {\n            degree[ng]--;\n            if (degree[ng] == 0)\n                q.push(ng); \n        }\n    }\n\n    for(auto &i:result)\n        cout << i << \" \";\n    cout << endl;\n}\nint main(){\n    graph g(6);\n    g[1].push_back(0);\n    g[1].push_back(2);\n    g[2].push_back(3);\n    g[3].push_back(4);\n    g[4].push_back(5);\n    kahn(g);\n    return 0; \n}\n

As for time complexity: we traverse all edges in the beginning (calculating degrees) and in the while segment we remove edges (once for an edge) and traverse all nodes. Hence, the time complexity of this algorithm is \\(O(V +E)\\). Note that this implementation assumes the graph is DAG. Try improving this code to support checking if the graph is DAG!

","tags":["Graph","Topological Sort"]},{"location":"graph/tree-traversals/","title":"Tree Traversals","text":"

The tree traversal is the process of visiting every node exactly once in a tree structure for some purposes(like getting information or updating information). In a binary tree there are some described order to travel, these are specific for binary trees but they may be generalized to other trees and even graphs as well.

a binary tree","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#preorder-traversal","title":"Preorder Traversal","text":"

Preorder means that a root will be evaluated before its children. In other words the order of evaluation is: Root-Left-Right

Preorder Traversal\n    Look Data\n    Traverse the left node\n    Traverse the right node\n

Example: 50 \u2013 7 \u2013 3 \u2013 2 \u2013 8 \u2013 16 \u2013 5 \u2013 12 \u2013 17 \u2013 54 \u2013 9 \u2013 13

","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#inorder-traversal","title":"Inorder Traversal","text":"

Inorder means that the left child (and all of the left child\u2019s children) will be evaluated before the root and before the right child and its children. Left-Root-Right (by the way, in binary search tree inorder retrieves data in sorted order)

Inorder Traversal\n    Traverse the left node\n    Look Data\n    Traverse the right node \n

Example: 2 \u2013 3 \u2013 7 \u2013 16 \u2013 8 \u2013 50 \u2013 12 \u2013 54 \u2013 17 \u2013 5 \u2013 9 \u2013 13

","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#postorder-traversal","title":"Postorder Traversal","text":"

Postorder is the opposite of preorder, all children are evaluated before their root: Left-Right-Root

Postorder Traversal\n    Traverse the left node\n    Traverse the right node \n    Look Data\n

Example: 2 \u2013 3 \u2013 16 \u2013 8 \u2013 7 \u2013 54 \u2013 17 \u2013 12 \u2013 13 \u2013 9 \u2013 5 \u2013 50

","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#implementation","title":"Implementation","text":"
class Node:\n    def __init__(self,key):\n        self.left = None\n        self.right = None\n        self.val = key\n\ndef printInorder(root):\n    if root:\n        printInorder(root.left)\n        print(root.val)\n        printInorder(root.right)\n\ndef printPostorder(root):\n    if root:\n        printPostorder(root.left)\n        printPostorder(root.right)\n        print(root.val)\n\ndef printPreorder(root):\n    if root:\n        print(root.val)\n        printPreorder(root.left)\n        printPreorder(root.right)\n
","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/union-find/","title":"Union Find","text":"

A disjoint-set data structure is a data structure that keeps track of a set of elements partitioned into a number of disjoint (non-overlapping) subsets. A union-find algorithm is an algorithm that performs two useful operations on such a data structure: [11, 12]

  • Find: Determine which subset a particular element is in. This can be used for determining if two elements are in the same subset.
  • Union: Join two subsets into a single subset
  • Union-Find Algorithm can be used to check whether an undirected graph contains cycle or not. This is another method based on Union-Find. This method assumes that graph doesn\u2019t contain any self-loops.
  • Most commonly used in kruskal's minumum spanning tree algorithm, it is used to check whether two nodes are in same connected component or not. [10]
","tags":["Graph","Union Find","Disjoint Set Union","DSU"]},{"location":"graph/union-find/#implementation","title":"Implementation","text":"
#include <bits/stdc++.h>\nusing namespace std;\n\ncont int MaxN=100005; // Max number of nodes\n\nint ancestor[MaxN];\n\nint parent(int k) // return the ancestor\n{\n    if(ancestor[k]==k) return k;\n    return ancestor[k] = parent(ancestor[k]); \n    // do not forget to equlize ancestor[k], it is going to decrease time complexity for the next operations\n}\n\nint MakeUnion(int a,int b) // setting parent of root(a) as root(b).\n{\n    a = parent(a);\n    b= parent(b);\n    ancestor[a] = b;\n}\nint find(int a,int b)\n{\n    return parent(a)==parent(b);\n}\n
","tags":["Graph","Union Find","Disjoint Set Union","DSU"]},{"location":"graph/union-find/#complexity","title":"Complexity","text":"

Using both path compression, splitting, or halving and union by rank or size ensures that the amortized time per operation is only \\(\\mathcal{O}(\\alpha (n))\\), which is optimal, where \\(\\alpha (n)\\) is the inverse Ackermann function. This function has a value \\(\\alpha (n)<5\\) for any value of n that can be written in this physical universe, so the disjoint-set operations take place in essentially constant time.

","tags":["Graph","Union Find","Disjoint Set Union","DSU"]},{"location":"introduction/","title":"Introduction","text":"

Editor: Muhammed Burak Bu\u011frul

Reviewers: Kadir Emre Oto & Yusuf Hakan Kalayc\u0131

"},{"location":"introduction/#introduction","title":"Introduction","text":"

First of all, this is an intensive algorithm programme prepared by inzva, which includes lectures, contests, problem-solvings and a variety of practises. \"Competitive Programming\" term will be mentioned frequently in this programme, especially for it's community, help in progress in algorithms and data structures etc.

Just for a quick cover up we will have a look at what happens when you compile and run a program, basic data types and functions. After that, we will examine C++ Standard Template Library(STL), time complexity and memory space.

"},{"location":"introduction/#command-line","title":"Command Line","text":"

A lot of people don't use command line if they can use an alternative. There are powerful IDEs (Integrated Development Environments) and they really make programming easier in some aspects. However, knowing how to use command line is important, especially for competitive programming. Firstly, it gives a low level knowledge and full control; secondly, every computer and environment has command line interface.

In this document, you will find only a basic introduction to the command line, which is no more than the basic usage of a file system, compiler, and programs.

There are a lot of differences between command line of Windows and Linux. But the differences between those of Mac and Linux are less.

"},{"location":"introduction/#linux-and-mac","title":"Linux and Mac","text":"

Mac users can use the built-in Terminal. You can find it by searching from Spotlight. Linux users can use gnome-terminal or any other installed one. Again, you can find them by using the built-in search tab.

Some basic commands:

  • ls list files in current directory. Usage: ls
  • cd change directory. Usage: cd ~/Desktop
  • mkdir make a new directory. Usage: mkdir directory_name
  • mv move command (cut). Usage: mv source_path destination_path
  • cp copy command. Usage: cp source_path destination_path
  • rm remove command. Usage: rm file_path

You can read more about the unix command line at: http://linuxcommand.org

"},{"location":"introduction/#compiling-and-executing-programs","title":"Compiling and Executing Programs","text":""},{"location":"introduction/#g","title":"G++","text":"

G++ is installed in Linux environments but in Mac, you should install Xcode first.

You can compile your cpp souce file by typing g++ source.cpp. Default output of this command is a.out.

"},{"location":"introduction/#running-executable-files","title":"Running Executable Files","text":"

For Linux and Mac, the command to run a program is ./program_name. If you use default g++ command, the name of your program will be a.out, so you should type ./a.out in order to run it.

"},{"location":"introduction/#closing-a-program","title":"Closing a Program","text":"

When you want to kill a program in running step, you can simply hit Control + C.

When you want to suspend a program in running step, you can simply hit Control + Z.

When you want to register EOF on standart input, you can simply hit Control + D.

"},{"location":"introduction/#inputoutput-redirection","title":"Input/Output Redirection","text":"

You can redirect input and output streams of a program by using command line and it is surprisingly easy.

"},{"location":"introduction/#saving-output-to-a-file","title":"Saving Output to a File","text":"

The only thing you need is > symbol. Just add it at the end of your run command with the output file name: ./a.out > output.txt

Note: This redirection process creates output.txt if it doesn't exist; otherwise deletes all content in it, then writes into it. If you want to use > in appending mode you should use >> instead.

"},{"location":"introduction/#reading-input-from-a-file","title":"Reading Input from a File","text":"

It is almost the same as output file redirection. The symbol is < now. Usage: ./a.out < input.txt

This will make your job easier than copying and pasting input to test your program, especially in the contests.

"},{"location":"introduction/#using-both-at-the-same-time","title":"Using Both at the Same Time","text":"

One of the wonderful things about these redirections is that they can be used at the same time. You can simply add both to the end of your run command: ./a.out < input.txt > output.txt

"},{"location":"introduction/#pipe","title":"pipe","text":"

Sometimes, you may want to redirect the output of a program to another program as input. You can use the | symbol for this. Usage: ./program1 | ./program2

"},{"location":"introduction/#diff","title":"diff","text":"

As the name denotes, it can check two files line by line if they are the same or not. If not, it outputs different lines. Usage: diff file1.txt file2.txt

It is very useful for comparing output of brute force solution and real solution.

"},{"location":"introduction/#structs-and-classes","title":"Structs and Classes","text":"

In almost every programming language, you can define your own data type. C++ has structs, classes; Python has dictionaries, classes etc. You can think of them as packets that store more than one different data and implement functions at the simplest level. They have a lot more abilities than these two (You can check OOP out).

Let us examine a fraction struct written in C++.

We need to store two values for a fraction, numerator and denominator.

struct Fraction {\n  int numerator, denominator;\n};\n

This is the simplest definition of a struct. Fraction struct contains two int variables. We call them members. So, Fraction struct has two members called numerator and denominator.

#include <cstdio>\n\nstruct Fraction {\n    int numerator, denominator;\n};\n\nFraction bigFraction(Fraction a, Fraction b) {\n\n    if( a.numerator * b.denominator > a.denominator * b.numerator )\n        return a;\n\n    return b;\n}\n\nint main() {\n    // Create two Fractions in order to compare them\n    Fraction a, b;\n\n    a.numerator = 15;\n    a.denominator = 20;\n\n    b.numerator = 12;\n    b.denominator = 18;\n\n    // Create a new Fraction in order to store biggest of Fraction a and Fraction b.\n    fraction biggest = bigFraction(a, b);\n\n    printf(\"The biggest fraction is %d / %d\\n\", biggest.numerator, biggest.denominator);\n    return 0;\n}\n

Let us do the same in Python3:

class Fraction:\n\n    def __init__(self, numerator, denominator):\n        self.numerator, self.denominator = numerator, denominator\n\ndef bigFraction(a, b):\n\n    if a.numerator * b.denominator > a.denominator * b.numerator:\n        return a\n\n    return b\n\na, b = Fraction(15, 20), Fraction(12, 18)  # Create two Fractions in order to compare them\nbiggest = bigFraction(a, b)\n\nprint(biggest.numerator, biggest.denominator)\n

In the sample codes above, a, b and biggest are called objects of Fraction. Also, the word instance can be used instead of object.

"},{"location":"introduction/#the-arrow-operator-c","title":"The Arrow Operator (C++)","text":"

Sometimes, usage of struct can change in C++. When you have a pointer to a struct, you should use -> to access its members instead of . operator. If you still want to use . operator, you should do in this way: (*ptr).member. But arrow operator is simpler: ptr->member.

"},{"location":"introduction/#big-o-notation","title":"Big O Notation","text":"

When dealing with algorithms or coming up with a solution, we need to calculate how fast our algorithm or solution is. We can calculate this in terms of number of operations. Big \\(\\mathcal{O}\\) notation moves in exactly at this point. Big \\(\\mathcal{O}\\) notation gives an upper limit to these number of operations. The formal definition of Big \\(\\mathcal{O}\\) is [1].

Let \\(f\\) be a real or complex valued function and \\(g\\) a real valued function, both defined on some unbounded subset of the real positive numbers, such that \\(g(x)\\) is strictly positive for all large enough values of \\(x\\). One writes:

\\[f(x) = \\mathcal{O}{(g(x))} \\ as\\ x \\rightarrow \\infty\\]

If and only if for all sufficiently large values of x, the absolute value of \\(f(x)\\) is at most a positive constant multiple of \\(g(x)\\). That is, \\(f(x)\\) = \\(\\mathcal{O}{(g(x))}\\) if and only if there exists a positive real number \\(M\\) and a real number \\(x_0\\) such that:

\\[|f(x)| \\leq Mg(x)\\ for \\ all\\ x\\ such\\ that\\ x_0 \\leq x\\]

In many contexts, the assumption that we are interested in the growth rate as the variable \\(x\\) goes to infinity is left unstated, and one writes more simply that:

\\[f(x) = \\mathcal{O}(g(x))\\]

Almost every case for competitive programming, basic understanding of Big \\(\\mathcal{O}\\) notation is enough to decide whether to implement a solution or not.

Note: Big \\(\\mathcal{O}\\) notation can be used for calculating both the run time complexity and the memory space used.

"},{"location":"introduction/#recursion","title":"Recursion","text":"

Recursion occurs when functions repeat themselves in order to create repeated applications or solve a problem by handling smaller situations first. There are thousands of examples in mathematics. One of the simple ones is factorial of \\(n\\). It can be shown by \\(n!\\) in mathematics and it gives the product of all positive integers from \\(1\\) to \\(n\\), for example, \\(4! = 1\\cdot 2\\cdot 3\\cdot 4 = 24\\). If we write factorial in a mathematical way, it will be:

\\[ \\begin{align*} f(n) &= \\begin{cases} 1 & \\text{if $n = 0$\\,\\, } \\\\ n \\cdot f(n - 1) & \\text{if $n > 0$\\,\\,} \\end{cases} \\end{align*} \\]

The reason why we didn't simply write it as \\(f(n) = n \\cdot f(n-1)\\) is that it doesn't give sufficient information about function. We should know where to end the function calls, otherwise it can call itself infinitely. Ending condition is \\(n = 0\\) here. We call it base case. Every recursive function needs at least one base case.

So if we write every step of \\(f(4)\\), it will be:

\\[ \\begin{align*} 4! &= 4\\cdot f(3) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot f(2) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot 2\\cdot f(1) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot 2\\cdot 1\\cdot f(0) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot 2\\cdot 1\\cdot 1 && \\text{base case} \\\\ &= 24 && \\text{arithmetic} \\end{align*} \\]

Basically, we can apply this recursive logic into programming:

int factorial(int n) {\n    int result = 1;\n    for(int i = 1; i <= n; i++)\n        res *= i;\n    return result;\n}\n

We can say a function is a recursive if it calls itself. Let us change this iterative factorial function into a recursive one. When you imagine how the recursive code will look like, you will notice it will look like the mathematical one:

int factorial(int n) {\n    if(n == 0)\n        return 1;\n    return n * factorial(n - 1);\n}\n

Note that we didn't forget to put our base case into the recursive function implementation.

"},{"location":"introduction/#time-complexity","title":"Time Complexity","text":"

In case above, it can be seen that both recursive and iterative implementations of factorial function runs in \\(\\mathcal{O}{(n)}\\) time. But this equality doesn't occur always. Let us examine fibonacci function, it is mathematically defines as:

\\[ \\begin{align*} f(n) &= \\begin{cases} 1 & \\text{if $n = 0$ or $n = 1$\\,\\, } \\\\ f(n - 1) + f(n - 2) & \\text{if $n > 1$\\,\\,} \\end{cases} \\end{align*} \\]

We can implement this function with just one for loop:

int fibonacci(int n) {\n    int result = 1, previous = 1;\n    for (int i = 2; i <= n; i++) {\n        int tmp = result;\n        result += previous;\n        previous = tmp;\n    }\n    return result;\n}\n

Again, we can implement recursive one according to the mathematical formula:

int fibonacci(int n) {\n    if( n == 0 || n == 1 )\n        return 1;\n    return fibonacci(n - 1) + fibonacci(n - 2);\n}\n

Let us calculate time complexity of iterative one. There are three basic operations inside a for loop that repeats \\(n-2\\) times. So time complexity is \\(\\mathcal{O}(n)\\). But what about the recursive one? Let us examine its recursion tree(diagram of function calls) for \\(n = 5\\) on visualgo.

\\(f\\) function called more than one for some values of n. Actually in every level, number of function calls doubles. So time complexity of the recursive implementation is \\(\\mathcal{O}{(2^n)}\\). It is far away worse than the iterative one. Recursive one can be optimized by techniques like memoization, but it is another topic to learn in further weeks.

"},{"location":"introduction/#mutual-recursion","title":"Mutual Recursion","text":"

Mutual recursion occurs when functions call each other. For example function f calls another function g, which also somehow calls f again.

Note: When using mutual recursions in C++, don't forget to declare one of the functions so that the other function can know first one from its' prototype.

Note 2: You can chain more than two functions and it will be still a mutual recursion.

"},{"location":"introduction/#enumeration-and-brute-force","title":"Enumeration and Brute-Force","text":"

Enumeration is numbering method on a set.

For example, permutation is one of enumeration techniques. First permutation of numbers in range \\(1\\) and \\(n\\) is:

\\[1, 2, 3... n-1, n\\]

And second one is:

\\[1, 2, 3... n, n-1\\]

Finally, the last one is:

\\[n, n-1... 3, 2, 1\\]

Additionally, we can try to enumerate all possible distributions of \\(n\\) elements into 3 different sets. An example of a distribution of 5 elements can be represented as:

\\[1, 1, 2, 1, 3\\]

In this distribution the first, the second and the fourth elements goes into the first set; third element goes into second set and the last element goes into the third set.

Enumerations can be done with recursive functions easily. We will provide example implementations of 3-set one. But before examining recursive implementation, let us try to implement iterative one:

#include <cstdio>\n\nint main(){\n\n    for( int i=1 ; i<=3 ; i++ )\n        for( int j=1 ; j<=3 ; j++ )\n            for( int k=1 ; k<=3 ; k++ )\n                for( int l=1 ; l<=3 ; l++ )\n                    for( int m=1 ; m<=3 ; m++ )\n                        printf(\"%d %d %d %d %d\\n\", i, j, k, l, m);\n\n    return 0;\n}\n

It will print all possible distributions of 5 elements into 3 sets. But what if we had 6 elements? Yes, we should have added another for loop. What if we had \\(n\\) elements? We can not add infinite number of for loops. But we can apply same logic with recursive functions easily:

#include <cstdio>\n\nint ar[100];\n\nvoid enumerate( int element, int n ){\n\n    if( element > n ){ // Base case\n\n        for( int i=1 ; i<=n ; i++ )\n            printf(\"%d \", ar[i]);\n\n        printf(\"\\n\");\n        return;\n    }\n\n    for( int i=1 ; i<=3 ; i++ ){\n        ar[element] = i;\n        enumerate(element + 1, n);\n    }\n}\n\nint main(){\n    enumerate(1, 5);\n    return 0;\n}\n

Brute-Force is trying all cases in order to achieve something(searching best, shortest, cheapest etc.).

One of the simplest examples of brute-forces approaches is primality checking. We know that for a prime \\(P\\) there is no positive integer in range \\([2, P-1]\\) that evenly divides \\(P\\). We can simply check all integers in this range to decide if it is prime:

bool isPrime(int N) {\n    for( int i=2 ; i<N ; i++ )\n        if( N % i == 0 )\n            return false;\n    return true;\n}\n

It is a simple function, but its' time complexity is \\(\\mathcal{O}(N)\\). Instead we can benefit from the fact if there is a positive integer \\(x\\) that evenly divides \\(N\\), there is a positive integer \\(\\frac{N}{x}\\) as well. As we know this fact, we can only check the integer in range \\([2, \\sqrt{N}]\\):

bool isPrime(int N) {\n    for( int i=2 ; i*i <= N ; i++ )\n        if( N % i == 0 )\n            return false;\n    return true;\n}\n

Now, its' time complexity is \\(\\mathcal{O}{(\\sqrt{N})}\\). It is far away better than \\(\\mathcal{O}{(N)}\\).

"},{"location":"introduction/#built-in-data-structures-and-functions","title":"Built-In Data Structures and Functions","text":"

There is no need to reinvent the wheel. Every language has its' own built in data structures, functions etc. After this point, the document will be C++ centered. But Python alternatives will be given.

"},{"location":"introduction/#the-c-standard-template-library-stl","title":"The C++ Standard Template Library (STL)","text":"

The STL is a well known library for C++ that includes variety of data structures and algorithms.

Note: Third party libraries generally not allowed in contests.

"},{"location":"introduction/#pairs","title":"Pairs","text":"

C++: Sometimes you may need to store two elements for an object. We can do this by creating a struct/class or two dimensional array. They will all work well but using pairs will be much more easier. You can think of pair as a class that has two variables named first and second. That's all for the basic. The good part is, you can decide their types(int, double, your own struct/class etc.). An example for pairs in C++:

#include <iostream>\n\nusing namespace std;\n\nint main(){\n\n    pair<int, int> p(1, 2);\n    pair<int, string> p2;\n\n    p2.first = 3;\n    p2.second = \"Hey there!\";\n\n    pair<pair<int, string>, string> nested;\n\n    nested.first = p2;\n    nested.second = \"This is a nested one\";\n\n    cout << \"Info of p -> \" << p.first << \" \" << p.second << endl;\n    cout << \"Info of p2 -> \" << p2.first << \" \" << p2.second << endl;\n    cout << \"Info of nested -> \" << nested.first.first << \" \" << nested.first.second\n            << \" \" << nested.second << endl;\n\n    return 0;\n}\n

Python: You can simply create a tuple or an array:

p = (1, 2)\np2 = [1, \"Hey there!\"]\nnested = ((3, \"inner?\"), \"outer\", \"this is a tuple you can add more\")\n\np2[0] = 3\n# nested[0] = \"don't\"  # In python you can't change tuples, but you can change arrays\n\nprint(p, p2, nested)\n
"},{"location":"introduction/#vectors","title":"Vectors","text":"

C++: When using array, we should decide its size. What if we don't have to do this, what if we could add elements into it without considering the current size? Well, all these ideas take us to vectors.

C++ has this structure. Its name is vector. It is a dynamic array but you don't have to think about its size. You can simply add elements into it. Like pairs, you can use it with any type (int, double, another vector, your struct/class etc.). Usage of a vector is very similar to classic array:

#include <iostream>\n#include <vector>\n\nusing namespace std;\n\nint main(){\n\n    vector<int> ar;\n\n    for( int i=0 ; i<10 ; i++ )\n        ar.push_back(i);\n\n    for( int i=0 ; i<(int)ar.size() ; i++ )\n        cout << ar[i] << \" \";\n\n    cout << endl;\n    return 0;\n}\n

Python: Python lists already behave like vectors:

ar = []\n\nfor i in range(10):\n    ar.append(i)\n\nprint(ar)\n
"},{"location":"introduction/#stacks-queues-and-deques","title":"Stacks, Queues, and Deques","text":"

C++: They are no different than stack, queue and deque we already know. It provides the implementation, you can simply include the libraries and use them. See queue, stack, deque.

"},{"location":"introduction/#priority-queues","title":"Priority Queues","text":"

It is basically a built-in heap structure. You can add an element in \\(\\mathcal{O}(logN)\\) time, get the first item in \\(O(logN)\\) time. The first item will be decided according to your choice of priority. This priority can be magnitude of value, enterence time etc.

C++: The different thing for priority queue is you should add #include <queue>, not <priority_queue>. You can find samples here. Again, you can define a priority queue with any type you want.

Note: Default priority_queue prioritizes elements by highest value first. Here is three ways of defining priority.

Python: You can use heapq in python.

"},{"location":"introduction/#sets-and-maps","title":"Sets and Maps","text":"

C++: Now that we mentioned binary trees (heap above), we can continue on built-in self balanced binary trees. Sets are key collections, and maps are key-value collections. Sets are useful when you want to add/remove elements in \\(\\mathcal{O}(logN)\\) time and also check existence of an item(key) in \\(O(logN)\\) time. Maps basically do the same but you can change value associated to a key without changing the position of the key in the tree. You can check c++ references for set and map. You can define them with any type you want. If you want to use them with your own struct/class, you must implement a compare function.

Python: You can use dictionaries for map and sets for set in python without importing any other libraries.

"},{"location":"introduction/#iterators","title":"Iterators","text":"

C++: You can use iterators for every built-in data structure in C++ for pointing their objects.

Python: You can iterate through any iterable in python by using in. You can check this example.

"},{"location":"introduction/#sorting","title":"Sorting","text":"

C++: In almost every language, there is a built-in sort function. C++ has one as well. It runs in \\(\\mathcal{O}(N log N)\\) time. You can pass your own compare function into sort function of C++.

Python: You can use sort function for any list or list like collection in order to sort them or if you don't want to change the original collection, you can use sorted() function instead. You can pass your own compare function into sort function of python by using key variable.

"},{"location":"introduction/#suggested-readings","title":"Suggested Readings","text":""},{"location":"introduction/#c","title":"C++","text":"
  • next_permutation: Link
  • STL document: Link
  • binary_search: Link
  • upper_bound: Link
  • lower_bound: Link
  • reverse: Link
  • fill: Link
  • count: Link
"},{"location":"introduction/#python","title":"Python","text":"
  • bisect: Link
  • collections: Link
  • built-in functions: Link
  • lambda: Link
"},{"location":"introduction/#references","title":"References","text":"
  1. Landau, Edmund (1909). Handbuch der Lehre von der Verteilung der Primzahlen [Handbook on the theory of the distribution of the primes] (in German). Leipzig: B. G. Teubner. p. 31.
"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0d8f77b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,183 @@ + + + + https://inzva.github.io/Algorithm-Program/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/algorithms/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/deque/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/fenwick-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/linked-list/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/lowest-common-ancestor/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/mo-algorithm/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/prefix-sum/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/queue/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/segment-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/sparse-table/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/sqrt-decomposition/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/stack/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/trie/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/bitmask-dp/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/common-dp-problems/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/digit-dp/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/dp-on-dags/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/dp-on-rooted-trees/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/dynamic-programming/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/greedy-algorithms/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/tree-child-sibling-notation/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/walk-counting-with-matrix/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/binary-search-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/bipartite-checking/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/breadth-first-search/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/bridges-and-articulation-points/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/cycle-finding/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/definitions/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/depth-first-search/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/heap/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/introduction/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/max-flow/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/minimum-spanning-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/representing-graphs/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/shortest-path/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/strong-connectivity-and-biconnectivity/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/strongly-connected-components/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/topological-sort/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/tree-traversals/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/union-find/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/introduction/ + 2025-03-07 + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000..388260d Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/docs/static/img/favicon.png b/static/img/favicon.png similarity index 100% rename from docs/static/img/favicon.png rename to static/img/favicon.png diff --git a/docs/static/img/logo.png b/static/img/logo.png similarity index 100% rename from docs/static/img/logo.png rename to static/img/logo.png diff --git a/docs/static/javascripts/katex.js b/static/javascripts/katex.js similarity index 100% rename from docs/static/javascripts/katex.js rename to static/javascripts/katex.js diff --git a/docs/static/stylesheets/main.css b/static/stylesheets/main.css similarity index 100% rename from docs/static/stylesheets/main.css rename to static/stylesheets/main.css