├── .deepsource.toml
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ └── feature_request.md
└── workflows
│ ├── codesee-arch-diagram.yml
│ └── python-app.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DESCRIPTION.txt
├── ISSUES.md
├── LICENSE.txt
├── README.md
├── assets
├── FOSSyt.PNG
├── Foss Hack 2020.JPG
├── PyconIndia-Full-lite.png
├── brsstack-mod.png
├── eduAlgo-def.png
├── haccktoberfest.png
├── jetbrains-variant-4.png
├── short_demo.PNG
├── tutorial1.PNG
├── vercel.PNG
├── winterupdate.PNG
└── woc.png
├── build
└── lib
│ └── edualgo
│ ├── __init__.py
│ └── algorithm.py
├── eduAlgo.egg-info
├── PKG-INFO
├── SOURCES.txt
├── dependency_links.txt
├── requires.txt
└── top_level.txt
├── edualgo
├── BinaryTree.py
├── LinkedList.py
├── Unbounded Knapsack (Rod cutting).py
├── __init__.py
├── algorithms
│ ├── KMP_Pattern_Matching.py
│ ├── __init__.py
│ ├── booyer_moore_voting.py
│ ├── matrices.py
│ ├── prime.py
│ ├── segment_tree.py
│ ├── sieve_of_eratosthenes.py
│ ├── sort.py
│ ├── stack_seq_finder.py
│ └── string_algorithms.py
├── backtracking_algorithms
│ ├── Knight’s_tour.py
│ ├── Rat_in_a_Maze.py
│ ├── Sudoku.py
│ ├── __init__.py
│ ├── m_coloring_problem.py
│ ├── n_queen.py
│ └── print_all_permutations_of_a_given_string.py
├── binSearchAlgo.py
├── circular-linked-list.py
├── dynamic_programming
│ ├── Fibonacci.py
│ ├── __init__.py
│ ├── climbing_stairs.py
│ ├── coin_change.py
│ ├── house_robber.py
│ ├── kadanes_algorithm.py
│ ├── knapsack.py
│ └── longest_common_subsequence.py
├── graph_algorithms
│ ├── Dijkstra_algorithms.py
│ ├── __init__.py
│ ├── kruskal.py
│ ├── prim.py
│ └── tsp.py
├── greedy_algorithms
│ ├── Minimum_Product_Subset.py
│ └── __init__.py
├── heap.py
├── maths
│ ├── __init__.py
│ ├── combinatorial.py
│ ├── fibonacci.py
│ ├── modular_arithmetic.py
│ └── primes.py
├── queue.py
├── radix-sort.py
├── search_algorithms
│ ├── __init__.py
│ ├── binary_search.py
│ ├── exponential_search.py
│ ├── interpolation_search.py
│ ├── jump_search.py
│ └── linear_search.py
├── stack.py
└── strings
│ ├── merge_string.py
│ ├── rotate_string.py
│ └── subsequences_string.py
├── images
├── Abhijit23.jpeg
└── eduAlgo.png
└── setup.py
/.deepsource.toml:
--------------------------------------------------------------------------------
1 | version = 1
2 |
3 | [[analyzers]]
4 | name = "python"
5 | enabled = true
6 |
7 | [analyzers.meta]
8 | runtime_version = "3.x.x"
9 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | open_collective: edualgo
4 | ko_fi: edualgo
5 | liberapay: edualgo-official
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/codesee-arch-diagram.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - master
5 | pull_request_target:
6 | types: [opened, synchronize, reopened]
7 |
8 | name: CodeSee Map
9 |
10 | jobs:
11 | test_map_action:
12 | runs-on: ubuntu-latest
13 | continue-on-error: true
14 | name: Run CodeSee Map Analysis
15 | steps:
16 | - name: checkout
17 | id: checkout
18 | uses: actions/checkout@v2
19 | with:
20 | repository: ${{ github.event.pull_request.head.repo.full_name }}
21 | ref: ${{ github.event.pull_request.head.ref }}
22 | fetch-depth: 0
23 |
24 | # codesee-detect-languages has an output with id languages.
25 | - name: Detect Languages
26 | id: detect-languages
27 | uses: Codesee-io/codesee-detect-languages-action@latest
28 |
29 | - name: Configure JDK 16
30 | uses: actions/setup-java@v2
31 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }}
32 | with:
33 | java-version: '16'
34 | distribution: 'zulu'
35 |
36 | # CodeSee Maps Go support uses a static binary so there's no setup step required.
37 |
38 | - name: Configure Node.js 14
39 | uses: actions/setup-node@v2
40 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }}
41 | with:
42 | node-version: '14'
43 |
44 | - name: Configure Python 3.x
45 | uses: actions/setup-python@v2
46 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }}
47 | with:
48 | python-version: '3.x'
49 | architecture: 'x64'
50 |
51 | - name: Configure Ruby '3.x'
52 | uses: ruby/setup-ruby@v1
53 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }}
54 | with:
55 | ruby-version: '3.0'
56 |
57 | # CodeSee Maps Rust support uses a static binary so there's no setup step required.
58 |
59 | - name: Generate Map
60 | id: generate-map
61 | uses: Codesee-io/codesee-map-action@latest
62 | with:
63 | step: map
64 | github_ref: ${{ github.ref }}
65 | languages: ${{ steps.detect-languages.outputs.languages }}
66 |
67 | - name: Upload Map
68 | id: upload-map
69 | uses: Codesee-io/codesee-map-action@latest
70 | with:
71 | step: mapUpload
72 | api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
73 | github_ref: ${{ github.ref }}
74 |
75 | - name: Insights
76 | id: insights
77 | uses: Codesee-io/codesee-map-action@latest
78 | with:
79 | step: insights
80 | api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
81 | github_ref: ${{ github.ref }}
82 |
--------------------------------------------------------------------------------
/.github/workflows/python-app.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 |
4 | name: Python application
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up Python 3.8
20 | uses: actions/setup-python@v2
21 | with:
22 | python-version: 3.8
23 | - name: Install dependencies
24 | run: |
25 | python -m pip install --upgrade pip
26 | pip install flake8 pytest
27 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
28 | - name: Lint with flake8
29 | run: |
30 | # stop the build if there are Python syntax errors or undefined names
31 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
32 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
33 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
34 | - name: Test with pytest
35 | run: |
36 | pytest
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | lib/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | *.egg-info/
22 | .installed.cfg
23 | *.egg
24 |
25 | # PyInstaller
26 | # Usually these files are written by a python script from a template
27 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
28 | *.manifest
29 | *.spec
30 |
31 | # Installer logs
32 | pip-log.txt
33 | pip-delete-this-directory.txt
34 |
35 | # Unit test / coverage reports
36 | htmlcov/
37 | .tox/
38 | .coverage
39 | .cache
40 | nosetests.xml
41 | coverage.xml
42 |
43 | # Translations
44 | *.mo
45 | *.pot
46 |
47 | # Django stuff:
48 | *.log
49 |
50 | # Sphinx documentation
51 | docs/_build/
52 |
53 | # PyBuilder
54 | target/
55 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at abhijittripathy99@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribution
2 |
3 | #### Hola Developer 🙌 !
4 |
5 | We are glad that you are enthusiastic enough to contribute to the python package. Thank you so much for your interest.
6 |
7 | Here are some steps to follow, if you want to contribute,
8 |
9 | * Have a look at the **issue** section and make some comments there if you are interested.
10 | * If you want to do the **documentation** work, please mail us at this mail addresses.
11 | * If you want to **sponsor** us, we are very much glad. Please mail us at this mail addresses.
12 |
--------------------------------------------------------------------------------
/DESCRIPTION.txt:
--------------------------------------------------------------------------------
1 |
2 | eduAlgo
3 |
4 | A simple python module to use different algorithms for educational purposes.
5 | This package is under development and planning process and it aims to hold many algorithms
6 | along with their implementations and complexities that can be used in educational purpose for all.
7 |
--------------------------------------------------------------------------------
/ISSUES.md:
--------------------------------------------------------------------------------
1 | ## Ongoing Issues
2 |
3 | Here is a list of algorithmic implementations using a linked list -
4 |
5 | #### Issue#1
6 |
7 | Can be viewed [here](https://github.com/Abhijit2505/eduAlgo/issues/1)
8 |
9 | * Palindromic Linked List -
10 | * Remove Linked List Elements -
11 | * Intersection Of Two Linked List -
12 | * Linked List Cycle -
13 | * Remove Duplicates From a Sorter List -
14 | * Merge Two Sorted List -
15 | * Reverse Linked List -
16 | * Delete Node In a Linked List -
17 | * Middle Of the Linked List -
18 | * Delete M Modes after M Nodes of a Linked List -
19 | * Convert Binary Number In a Linked List to integer -
20 |
21 | #### issue#2
22 |
23 | Can be viewed [here](https://github.com/Abhijit2505/eduAlgo/issues/2)
24 |
25 | * Design Linked List -
26 | * Rotate List -
27 | * Insert Into a Sorted Circular Linked List -
28 | * Add Two Numbers -
29 | * Remove Nth Node From End of List -
30 | * Copy List with Random Pointer -
31 | * Remove Duplicates From The Sorted List (Second Version) -
32 | * Reorder List -
33 | * Linked List Cycle (Second Version) -
34 | * Reverse Linked List (Second Version) -
35 | * Linked List In Binary Tree -
36 | * Insertion Sort List -
37 | * Remove Zero-Sum Consecutive Nodes from Linked List -
38 | * Partition List -
39 | * Sort List -
40 | * Design Phone Directory -
41 | * Convert Sorted List to Binary Search Tree -
42 | * Swap Nodes in Pairs -
43 | * Split Linked List in Parts -
44 | * Add Two Numbers(Second Version) -
45 | * Flatten a Multilevel Doubly Linked List -
46 | * Odd-Even Linked List -
47 | * Linked List Components -
48 | * Next Greater Node in Linked List -
49 | * Plus One Linked List -
50 | * Convert Binary Search Tree to Sorted Doubly Linked List -
51 |
52 | #### Issue#3
53 |
54 | Can be viewed [here](https://github.com/Abhijit2505/eduAlgo/issues/3)
55 |
56 | * Reverse Nodes in k-Group -
57 | * Merge k Sorted Lists -
58 |
59 | The addition of code for these implementations is ongoing.
60 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Abhijit Tripathy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 
3 |
4 |
5 |
6 |
7 | ## Objective
8 | A python package published at [PyPi](https://pypi.org/). The project can be viewed here => [PyPi - eduAlgo](https://pypi.org/project/eduAlgo/).
9 | **Don't forget to create an ISSUE before making a PR and always make PR to this repo - [Main eduAlgo](https://github.com/edualgo/eduAlgo)**
10 |
11 | ## Stats
12 |
13 |
14 |
15 | [](https://github.com/eduAlgo/eduAlgo/graphs/commit-activity)
16 | [](https://pypi.python.org/pypi/eduAlgo/)
17 | [](https://GitHub.com/eduAlgo/eduAlgo/graphs/contributors/)
18 |
19 |
20 | [](https://pepy.tech/project/edualgo)
21 | [](https://pepy.tech/project/edualgo)
22 | [](https://pepy.tech/project/edualgo)
23 |
24 | [](https://forthebadge.com) [](https://forthebadge.com) [](https://forthebadge.com)
25 |
26 | ## Aim Of The Package
27 |
28 | This is a very simple python package made up with python script to study different algorithms for educational purposes. This package is currently under **planning** version and aims to achieve the following :-
29 |
30 | * To put together all the available algorithms
31 | * Help students with learning space and time complexity
32 | * Visualizing Algorithms
33 | * Getting resources, articles etc. to study about python and Algorithms
34 | * Become a handy tool for the programmers while using different algorithms on daily basis
35 |
36 | ## Organization
37 |
38 | This project is a part of the organization Edualgo Academy.
39 |
40 | > We are an opensource organization having a few open-sourced projects on github related to Data structures and Algorithms in Python, Flutter Development & Frontend Development.
41 | chek the organization here - eduAlgo
42 |
43 | ## Documentation
44 | The documentation for the included methods and their implementations can be found here => eduAlgo-Documentation
45 |
46 | ## Algorithms Yet to Publish
47 |
48 | * Searching Algorithms and Visualizations
49 | * Sorting Algorithms and Visualizations
50 | * Graph Algorithms and Visualizations
51 | * Linked List Implementations and Vizualizations
52 | * Tree Types, Vizualizations and Implementations
53 |
54 | ## Installation
55 |
56 | Fast install:
57 |
58 | pip install eduAlgo
59 |
60 | Example
61 |
62 | ```python
63 |
64 | from edualgo import LinkedList as ll
65 | llist1 = ll.linkedlist()
66 | llist2 = ll.linkedlist()
67 |
68 | arr1 = list(map(int,input().split()))
69 | arr2 = list(map(int,input().split()))
70 |
71 | for i in arr1:
72 | llist1.append(i)
73 |
74 | for i in arr2:
75 | llist2.append(i)
76 |
77 | sol = ll.list_algorithms()
78 |
79 | llist3 = ll.linkedlist()
80 | llist3.head = sol.mergeTwoLists(llist1.head,llist2.head)
81 | llist3.printLL()
82 | ```
83 | Input:
84 |
85 | 1 2 3
86 | 2 3 4
87 |
88 | Output:
89 |
90 | 1 2 2 3 3 4
91 |
92 | ## Communities/Hackathon/Conferences (In which the project was a part of)
93 |
94 |
95 |
96 |
97 | 
98 | FOSS Hack - 2020 (12th & 13th September 2020)
99 | |
100 |
101 | 
102 | PyCon - 2020 Devsprint ( 04th & 05th October 2020)
103 | |
104 |
105 |
106 |
107 | 
108 | Hacktoberfest 2020 (October 2020)
109 | |
110 |
111 | 
112 | Winter of Code - DSC, NSEC
113 | |
114 |
115 |
116 |
117 |
118 |
119 | ## Latest Winter Update (Package Demo)
120 |
121 |
122 |
123 | ## Tutorials
124 |
125 |
126 |
127 |
128 | ## License
129 |
130 | This package is under **MIT License** copyright @Abhijit Tripathy. The production code can be checked at the *production* branch of this repository.
131 |
132 | ## Our sponsors
133 |
134 |
174 |
175 | ## About The Creator
176 |
177 |
178 |
179 |
180 |
181 | |
182 |
183 | Abhijit Tripathy
184 | DSA Developer and Python Programmer
185 | |
186 |
187 |
188 |
189 | ## Our contributors
190 |
191 |
192 |
193 |
194 |
195 | Made with [contrib.rocks](https://contrib.rocks).
196 |
--------------------------------------------------------------------------------
/assets/FOSSyt.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/FOSSyt.PNG
--------------------------------------------------------------------------------
/assets/Foss Hack 2020.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/Foss Hack 2020.JPG
--------------------------------------------------------------------------------
/assets/PyconIndia-Full-lite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/PyconIndia-Full-lite.png
--------------------------------------------------------------------------------
/assets/brsstack-mod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/brsstack-mod.png
--------------------------------------------------------------------------------
/assets/eduAlgo-def.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/eduAlgo-def.png
--------------------------------------------------------------------------------
/assets/haccktoberfest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/haccktoberfest.png
--------------------------------------------------------------------------------
/assets/jetbrains-variant-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/jetbrains-variant-4.png
--------------------------------------------------------------------------------
/assets/short_demo.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/short_demo.PNG
--------------------------------------------------------------------------------
/assets/tutorial1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/tutorial1.PNG
--------------------------------------------------------------------------------
/assets/vercel.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/vercel.PNG
--------------------------------------------------------------------------------
/assets/winterupdate.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/winterupdate.PNG
--------------------------------------------------------------------------------
/assets/woc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/assets/woc.png
--------------------------------------------------------------------------------
/build/lib/edualgo/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/eduAlgo.egg-info/PKG-INFO:
--------------------------------------------------------------------------------
1 | Metadata-Version: 2.1
2 | Name: eduAlgo
3 | Version: 1.1.6.3
4 | Summary: An educational Algorithmic Library
5 | Home-page: https://github.com/Abhijit2505/eduAlgo
6 | Author: Abhijit Tripathy
7 | Author-email: abhijittripathy99@gmail.com
8 | License: MIT
9 | Description:
10 |
11 |
12 | # eduAlgo
13 |
14 |
15 |
16 |
17 |
18 |
19 | [](https://forthebadge.com) [](https://forthebadge.com) [](https://forthebadge.com)
20 |
21 | ## Objective
22 | A python package published at [PyPi](https://pypi.org/). The project can be viewed here - [PyPi - eduAlgo](https://pypi.org/project/eduAlgo/).
23 |
24 | ## Aim Of The Package
25 |
26 | This is a very simple python package made with python script to study different algorithms for educational purposes. This package is under **planning** version and aims to achieve the following,
27 |
28 | * Contain All the available algorithms
29 | * Help students with learning space and time complexity
30 | * Visualizing Algorithms
31 | * Getting resources, articles etc to study about python and Algorithms
32 | * Become a handy tool for the programmers while using different algorithms on daily basis
33 |
34 | ## Documentation
35 | The documentation for the included methods and their implementations can be found here - eduAlgo-Documentation
36 |
37 | ## Algorithms Yet to Publish
38 |
39 | * Searching Algorithms and Visualizations
40 | * Sorting Algorithms and Visualizations
41 | * Graph Algorithms and Visualizations
42 | * Linked List Implementations and Vizualizations
43 | * Tree Types, Vizualizations and Implementations
44 |
45 | ## Installation
46 |
47 | Fast install:
48 |
49 | pip install eduAlgo
50 |
51 | Example
52 |
53 | ```python
54 |
55 | from edualgo import LinkedList as ll
56 | llist1 = ll.linkedlist()
57 | llist2 = ll.linkedlist()
58 |
59 | arr1 = list(map(int,input().split()))
60 | arr2 = list(map(int,input().split()))
61 |
62 | for i in arr1:
63 | llist1.append(i)
64 |
65 | for i in arr2:
66 | llist2.append(i)
67 |
68 | sol = ll.list_algorithms()
69 |
70 | llist3 = ll.linkedlist()
71 | llist3.head = sol.mergeTwoLists(llist1.head,llist2.head)
72 | llist3.printLL()
73 | ```
74 | Input:
75 |
76 | 1 2 3
77 | 2 3 4
78 |
79 | Output:
80 |
81 | 1 2 2 3 3 4
82 |
83 | ## License
84 |
85 | This package is under **MIT License** copyright @Abhijit Tripathy
86 |
87 | ## About The Contributors
88 |
89 |
90 |
91 |
92 |
93 | |
94 |
95 | Abhijit Tripathy
96 | DSA Developer and Python Programmer
97 | |
98 |
99 |
100 |
101 | Keywords: algorithms
102 | Platform: UNKNOWN
103 | Classifier: Development Status :: 3 - Alpha
104 | Classifier: Intended Audience :: Education
105 | Classifier: Topic :: Education
106 | Classifier: License :: OSI Approved :: MIT License
107 | Classifier: Programming Language :: Python :: 3.7
108 | Description-Content-Type: text/markdown
109 |
--------------------------------------------------------------------------------
/eduAlgo.egg-info/SOURCES.txt:
--------------------------------------------------------------------------------
1 | README.md
2 | setup.py
3 | eduAlgo.egg-info/PKG-INFO
4 | eduAlgo.egg-info/SOURCES.txt
5 | eduAlgo.egg-info/dependency_links.txt
6 | eduAlgo.egg-info/requires.txt
7 | eduAlgo.egg-info/top_level.txt
8 | edualgo/BinaryTree.py
9 | edualgo/LinkedList.py
10 | edualgo/__init__.py
11 | edualgo/algorithm.py
--------------------------------------------------------------------------------
/eduAlgo.egg-info/dependency_links.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/eduAlgo.egg-info/requires.txt:
--------------------------------------------------------------------------------
1 | requests
2 |
--------------------------------------------------------------------------------
/eduAlgo.egg-info/top_level.txt:
--------------------------------------------------------------------------------
1 | edualgo
2 |
--------------------------------------------------------------------------------
/edualgo/BinaryTree.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 | import collections
3 | class Node:
4 | def __init__(self, val):
5 |
6 | self.left = None
7 | self.right = None
8 | self.val = val
9 |
10 | def insert(self, val):
11 | if self.val:
12 | if val < self.val:
13 | if self.left is None:
14 | self.left = Node(val)
15 | else:
16 | self.left.insert(val)
17 | else:
18 | if self.right is None:
19 | self.right = Node(val)
20 | else:
21 | self.right.insert(val)
22 | else:
23 | self.val = val
24 |
25 | class BinaryTreeAlgorithms:
26 | def print_tree(self,root,hint=False):
27 | if(hint is True):
28 | self.print_tree_hint()
29 | if root is None:
30 | return
31 | print(root.val,end =":")
32 | if root.left:
33 | print("L: {} ,".format(root.left.val),end ="")
34 | if root.right:
35 | print("R: {} ,".format(root.right.val),end="")
36 | print("\n")
37 | self.print_tree(root.left)
38 | self.print_tree(root.right)
39 |
40 | def print_tree_hint(self):
41 | message = """
42 | Printing A Binary Tree
43 | ------------------------------------
44 |
45 | Purpose : Printing a Binary Tree(Both Left and Right Node)
46 | Method : Recursion, Binary Tree
47 |
48 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
49 |
50 | Hint :
51 | Print the root, use recursion and call into the left and right
52 |
53 | Pseudocode :
54 | --> if(root is None) return
55 | --> print(root.value)
56 | --> print(root.left.value)
57 | --> print(root.right.value)
58 | --> make recursion calls,
59 | print_tree(root.left)
60 | print.tree(root.right)
61 |
62 | Visualization:
63 |
64 | Given Binary Tree :
65 |
66 | +------+
67 | | 12 | <-- root
68 | +------+
69 | / \\
70 | / \\
71 | +------+ +------+
72 | root.left --> | 6 | | 14 | <-- root.right
73 | +------+ +------+
74 | / \\ / \\
75 | / \\ / \\
76 | +------+ +------+ +------+ +------+
77 | | 3 | | 7 | | 12 | | 15 |
78 | +------+ +------+ +------+ +------+
79 |
80 |
81 | Step 1: print root, root.left and root.right
82 |
83 | 12 : L:6, R: 14
84 |
85 | Step 2 : call recursive functions
86 |
87 | f(root.left) :
88 |
89 | +------+
90 | | 6 | <-- root
91 | +------+
92 | / \\
93 | / \\
94 | +------+ +------+
95 | root.left --> | 3 | | 7 | <-- root.right
96 | +------+ +------+
97 |
98 | +------------------------+
99 | | Repeat Step 1 & Step 2 | <-- recursion calls
100 | +------------------------+
101 |
102 | f(root.right) :
103 |
104 | +------+
105 | | 14 | <-- root
106 | +------+
107 | / \\
108 | / \\
109 | +------+ +------+
110 | root.left --> | 12 | | 15 | <-- root.right
111 | +------+ +------+
112 |
113 | +------------------------+
114 | | Repeat Step 1 & Step 2 | <-- recursion calls
115 | +------------------------+
116 |
117 | Finally The Output :
118 |
119 | -------------------------
120 | | 12:L: 6 ,R: 14 , |
121 | | |
122 | | 6:L: 3 ,R: 7 , |
123 | | |
124 | | 3: |
125 | | |
126 | | 7: |
127 | | |
128 | | 14:L: 12 ,R: 15 , |
129 | | |
130 | | 12: |
131 | | |
132 | | 15: |
133 | -------------------------
134 |
135 | Learn More:
136 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
137 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
138 | """
139 | print_msg_box(message)
140 |
141 | def Inorder_print(self,root,hint=False):
142 | if(hint is True):
143 | self.Inorder_print_hint()
144 | if root is None:
145 | return
146 | self.Inorder_print(root.left)
147 | print(root.val,end =", ")
148 | self.Inorder_print(root.right)
149 |
150 | def Inorder_print_hint(self):
151 | message = """
152 | Printing A Binary Tree InOrder Traversal
153 | ------------------------------------
154 |
155 | Purpose : Printing a Binary Tree(InOrder Traversal)
156 | Method : Recursion, Binary Tree
157 |
158 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
159 |
160 | Hint :
161 | print order -> LEFT -- ROOT -- RIGHT
162 | Call into left recursively till exist,Print the root, use recursion to call into the right
163 |
164 | Pseudocode :
165 | --> if(root is None) return
166 | --> print(root.left.value)
167 | --> print(root.value)
168 | --> print(root.right.value)
169 |
170 | Visualization:
171 |
172 | Given Binary Tree :
173 |
174 | +------+
175 | | 12 | <-- root
176 | +------+
177 | / \\
178 | / \\
179 | +------+ +------+
180 | root.left --> | 6 | | 14 | <-- root.right
181 | +------+ +------+
182 | / \\ / \\
183 | / \\ / \\
184 | +------+ +------+ +------+ +------+
185 | | 3 | | 7 | | 13 | | 15 |
186 | +------+ +------+ +------+ +------+
187 |
188 |
189 | step : call recursive functions on root.left, print root, call on right
190 |
191 | f(root.left) :
192 |
193 | +------+
194 | | 3 | <-- root
195 | +------+
196 | / \\
197 | / \\
198 | +------+ +------+
199 | root.left --> | None | | None | <-- root.right
200 | +------+ +------+
201 |
202 | output : LEFT -- ROOT -- RIGHT
203 | None 3 None
204 |
205 |
206 | +------+
207 | | 6 | <-- root
208 | +------+
209 | / \\
210 | / \\
211 | +------+ +------+
212 | root.left --> | 3 | | 7 | <-- root.right
213 | +------+ +------+
214 |
215 | output : LEFT -- ROOT -- RIGHT
216 | 3 6 7
217 |
218 | f(root.right) :
219 |
220 | +------+
221 | | 14 | <-- root
222 | +------+
223 | / \\
224 | / \\
225 | +------+ +------+
226 | root.left --> | 13 | | 15 | <-- root.right
227 | +------+ +------+
228 |
229 | output : LEFT -- ROOT -- RIGHT
230 | 13 14 15
231 |
232 | Finally The Output :
233 |
234 | ---------------------------------
235 | | 3, 6, 7, 12, 13, 14, 15, |
236 | ---------------------------------
237 |
238 | Learn More:
239 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
240 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
241 | """
242 | print_msg_box(message)
243 |
244 | def Preorder_print(self,root,hint=False):
245 | if(hint is True):
246 | self.Preorder_print_hint()
247 | if root is None:
248 | return
249 | print(root.val,end =", ")
250 | self.Preorder_print(root.left)
251 | self.Preorder_print(root.right)
252 |
253 | def Preorder_print_hint(self):
254 | message = """
255 | Printing A Binary Tree PreOrder Traversal
256 | ------------------------------------
257 |
258 | Purpose : Printing a Binary Tree(PreOrder Traversal)
259 | Method : Recursion, Binary Tree
260 |
261 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
262 |
263 | Hint :
264 | print order -> ROOT -- LEFT -- RIGHT
265 | Print the root, use recursion to call into the left and the right subtree
266 |
267 | Pseudocode :
268 | --> if(root is None) return
269 | --> print(root.value)
270 | --> print(root.left.value)
271 | --> print(root.right.value)
272 |
273 | Visualization:
274 |
275 | Given Binary Tree :
276 |
277 | +------+
278 | | 12 | <-- root
279 | +------+
280 | / \\
281 | / \\
282 | +------+ +------+
283 | root.left --> | 6 | | 14 | <-- root.right
284 | +------+ +------+
285 | / \\ / \\
286 | / \\ / \\
287 | +------+ +------+ +------+ +------+
288 | | 3 | | 7 | | 13 | | 15 |
289 | +------+ +------+ +------+ +------+
290 |
291 |
292 | step 1 : Print the root value
293 |
294 | +------+
295 | | 6 | <-- root
296 | +------+
297 | / \\
298 | / \\
299 | +------+ +------+
300 | root.left --> | 3 | | 7 | <-- root.right
301 | +------+ +------+
302 |
303 | output : 6
304 |
305 | f(root.left) :
306 |
307 | +------+
308 | | 3 | <-- root
309 | +------+
310 | / \\
311 | / \\
312 | +------+ +------+
313 | root.left --> | None | | None | <-- root.right
314 | +------+ +------+
315 |
316 | output : ROOT -- LEFT -- RIGHT
317 | 3 None None
318 |
319 | f(root.right) :
320 |
321 | +------+
322 | | 14 | <-- root
323 | +------+
324 | / \\
325 | / \\
326 | +------+ +------+
327 | root.left --> | 13 | | 15 | <-- root.right
328 | +------+ +------+
329 |
330 | output : ROOT -- LEFT -- RIGHT
331 | 14 13 15
332 |
333 | Finally The Output :
334 |
335 | ---------------------------------
336 | | 12, 6, 3, 7, 14, 13, 15, |
337 | ---------------------------------
338 |
339 | Learn More:
340 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
341 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
342 | """
343 | print_msg_box(message)
344 |
345 | def Postorder_print(self,root,hint=False):
346 | if(hint is True):
347 | self.Postorder_print_hint()
348 | if root is None:
349 | return
350 | self.Postorder_print(root.left)
351 | self.Postorder_print(root.right)
352 | print(root.val,end =", ")
353 |
354 | def Postorder_print_hint(self):
355 | message = """
356 | Printing A Binary Tree PostOrder Traversal
357 | ------------------------------------
358 |
359 | Purpose : Printing a Binary Tree(PostOrder Traversal)
360 | Method : Recursion, Binary Tree
361 |
362 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
363 |
364 | Hint :
365 | print order -> LEFT -- RIGHT -- ROOT
366 | use recursion to call into the left and the right subtree, Print the root
367 |
368 | Pseudocode :
369 | --> if(root is None) return
370 | --> print(root.left.value)
371 | --> print(root.right.value)
372 | --> print(root.value)
373 |
374 | Visualization:
375 |
376 | Given Binary Tree :
377 |
378 | +------+
379 | | 12 | <-- root
380 | +------+
381 | / \\
382 | / \\
383 | +------+ +------+
384 | root.left --> | 6 | | 14 | <-- root.right
385 | +------+ +------+
386 | / \\ / \\
387 | / \\ / \\
388 | +------+ +------+ +------+ +------+
389 | | 3 | | 7 | | 13 | | 15 |
390 | +------+ +------+ +------+ +------+
391 |
392 |
393 | step 1 : Print the left, print right, print root
394 |
395 | +------+
396 | | 6 | <-- root
397 | +------+
398 | / \\
399 | / \\
400 | +------+ +------+
401 | root.left --> | 3 | | 7 | <-- root.right
402 | +------+ +------+
403 |
404 |
405 | output : LEFT -- RIGHT -- ROOT
406 | 3 7 6
407 |
408 |
409 | Finally The Output :
410 |
411 | ---------------------------------
412 | | 3, 7, 6, 13, 15, 14, 12 |
413 | ---------------------------------
414 |
415 | Learn More:
416 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
417 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
418 | """
419 | print_msg_box(message)
420 |
421 | def rangeSumBST(self, root,L,R):
422 | if(root is None):
423 | return 0
424 | sum1 = 0; sum2 = 0
425 | if(root.left):
426 | sum1 = self.rangeSumBST(root.left,L,R)
427 | if(root.right):
428 | sum2 = self.rangeSumBST(root.right,L,R)
429 | if((root.val >= L )and (root.val <= R)):
430 | return root.val + sum1 + sum2
431 | else:
432 | return sum1 + sum2
433 |
434 | def mergeTrees(self, t1, t2):
435 | if(t1 is None and t2 is None):
436 | return None
437 | if(t2 is None):
438 | return t1
439 | if(t1 is None):
440 | return t2
441 | t1.val = t1.val + t2.val
442 | t1.left = self.mergeTrees(t1.left,t2.left)
443 | t1.right = self.mergeTrees(t1.right,t2.right)
444 | return t1
445 |
446 | def sumOfLeftLeaves(self, root):
447 | if(root is None):
448 | return 0
449 | sum = 0
450 | if(root.left is not None and (root.left.left is None and root.left.right is None)):
451 | sum = root.left.val
452 | return sum + self.sumOfLeftLeaves(root.left)+self.sumOfLeftLeaves(root.right)
453 |
454 | def isSameTree(self, p, q):
455 | if(p is None and q is None):
456 | return True
457 | if(p is None or q is None):
458 | return False
459 | return (p.val == q.val) and (self.isSameTree(p.left,q.left)) and (self.isSameTree(p.right,q.right))
460 |
461 | def isCousins(self, root, x, y):
462 | if not root:
463 | return root
464 | queue = collections.deque([root])
465 | level = set()
466 | last = n_last = root
467 | while any(queue):
468 | node = queue.popleft()
469 | same_father = set()
470 | if node.left:
471 | level.add(node.left.val)
472 | queue.append(node.left)
473 | n_last = node.left
474 | same_father.add(node.left.val)
475 | if node.right:
476 | level.add(node.right.val)
477 | queue.append(node.right)
478 | n_last = node.right
479 | same_father.add(node.right.val)
480 | if x in same_father and y in same_father:
481 | return False
482 | if node == last:
483 | last = n_last
484 | if x in level and y in level:
485 | return True
486 | level = set()
487 | return False
488 |
489 | def countNode(self,root):
490 | '''
491 | countNode will take root node
492 | as input and return the number
493 | node present in the tree.
494 | '''
495 | if (root is None):
496 | return 0
497 | return 1 + self.countNode(root.left) + self.countNode(root.right)
498 |
499 | def KthLevel(self,root, k):
500 | '''
501 | KthLevel will take root node and level value (k),
502 | and print the element present at that level
503 | Note: level for the root node is 1
504 | '''
505 | if (root is None):
506 | return
507 | if (k ==1):
508 | print(root.data,end=', ')
509 | return
510 | self.KthLevel(root.left, k-1)
511 | self.KthLevel(root.right, k-1)
512 | return
513 |
514 |
515 | #root1 = Node(12)
516 | #root1.insert(6)
517 | #root1.insert(14)
518 | #root1.insert(3)
519 | #root1.insert(7)
520 | #root1.insert(15)
521 | #root1.insert(13)
522 | # ping = BinaryTreeAlgorithms()
523 | # ping.Inorder_print(root1)
524 | # ping.Preorder_print(root1)
525 | # ping.Postorder_print(root1)
526 |
527 |
528 |
--------------------------------------------------------------------------------
/edualgo/LinkedList.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 |
3 | class Node:
4 | def __init__(self,val):
5 | self.val = val
6 | self.next = None
7 |
8 | class linkedlist:
9 | def __init__(self):
10 | self.head = None
11 | self.tail = None
12 |
13 | def append(self,val):
14 | if self.tail is None:
15 | self.head = Node(val)
16 | self.tail = self.head
17 |
18 | else:
19 | self.tail.next = Node(val)
20 | self.tail = self.tail.next
21 |
22 | def printLL(self):
23 | temp = self.head
24 | while(temp):
25 | print(temp.val, end =" ")
26 | temp = temp.next
27 |
28 | class list_algorithms:
29 |
30 | def length(self,head):
31 | temp = head
32 | count = 0
33 | while(temp):
34 | temp = temp.next
35 | count += 1
36 | return count
37 |
38 | def reverse_linked_recursive(self,head):
39 | if(head is None or head.next is None):
40 | return head
41 | small_head = self.reverse_linked_recursive(head.next)
42 | head.next = None
43 | temp = small_head
44 | while(temp.next is not None):
45 | temp = temp.next
46 | temp.next = head
47 | head = small_head
48 | return head
49 |
50 | def reverse_linked_iterative(self,head):
51 | if(head is None or head.next is None):
52 | return head
53 | prev = None
54 | curr = head
55 | while(curr):
56 | temp = curr.next
57 | curr.next = prev
58 | prev = curr
59 | curr = temp
60 | return prev
61 |
62 | def is_palindrome(self,head):
63 | stack = []
64 | temp = head
65 | while(temp):
66 | stack.append(temp.val)
67 | temp = temp.next
68 | temp = head
69 | while(temp):
70 | if(stack[-1] != temp.val):
71 | return False
72 | else:
73 | stack.pop()
74 | temp = temp.next
75 | return True
76 |
77 | def is_palindrome_optimized(self,head):
78 | len = self.length(head)
79 | if(len <= 1):
80 | return True
81 | count = 0
82 | head2 = head
83 | prev = None
84 | while(count < int(len/2)):
85 | temp = head2.next
86 | head2.next = prev
87 | prev = head2
88 | head2 = temp
89 | count+=1
90 | head = head2
91 | head2 = prev
92 | if(len % 2 == 1):
93 | head = head.next
94 | while((head2 is not None) and (head is not None)):
95 | if(head2.val != head.val):
96 | return False
97 | head = head.next
98 | head2 = head2.next
99 | return True
100 |
101 | def delete_sorted_duplicate(self,head):
102 | if(head is None or head.next is None):
103 | return head
104 | small_head = self.delete_sorted_duplicate(head.next)
105 | while((small_head is not None) and (head.val == small_head.val)):
106 | temp = small_head
107 | small_head = small_head.next
108 | temp.next = None
109 |
110 | head.next = small_head
111 | return head
112 |
113 | def delete_node_by_value(self, head, value):
114 | # if head is None
115 | if head is None:
116 | return None
117 | prev = None
118 | current = head
119 | # get node to delete
120 | while current:
121 | if current.val == value:
122 | break
123 | prev = current
124 | current = current.next
125 | # if the node is the head
126 | if prev is None:
127 | # return new head
128 | return head.next
129 | # if value not found
130 | if current is None:
131 | return head
132 | prev.next = current.next
133 | return head
134 |
135 | def middleNode(self,head):
136 | slow = fast = head
137 | while fast and fast.next:
138 | slow = slow.next
139 | fast = fast.next.next
140 | return slow
141 |
142 | def mergeTwoLists(self, l1, l2):
143 | if(l1 is None):
144 | return l2
145 | if((l2 is not None) and (l2.val < l1.val)):
146 | l1,l2 = l2,l1
147 | l1.next = self.mergeTwoLists(l1.next,l2)
148 | return l1
149 |
150 | def removeElements(self,head,val):
151 | if(head is None):
152 | return head
153 | small_head = self.removeElements(head.next,val)
154 | if(head.val == val):
155 | head = small_head
156 | else:
157 | head.next = small_head
158 | return head
159 |
160 | def getIntersectionNode(self,headA,headB):
161 | tempA = headA
162 | tempB = headB
163 |
164 | lengthA = 0
165 | lengthB = 0
166 |
167 | while(tempA):
168 | lengthA += 1
169 | tempA = tempA.next
170 | while(tempB):
171 | lengthB += 1
172 | tempB = tempB.next
173 |
174 | tempA = headA
175 | tempB = headB
176 |
177 | while(lengthA > lengthB):
178 | tempA = tempA.next
179 | lengthA -= 1
180 | while(lengthB > lengthA):
181 | tempB = tempB.next
182 | lengthB -= 1
183 |
184 | while((tempA != tempB) and (tempA is not None)):
185 | tempA = tempA.next
186 | tempB = tempB.next
187 |
188 | if((tempA == tempB) and (tempA is not None)):
189 | return tempA
190 | else:
191 | return None
192 |
193 | def getDecimalValue(self,head):
194 | temp = head
195 | length = 0
196 | while(temp):
197 | length += 1
198 | temp = temp.next
199 |
200 | num = 0
201 | temp = head
202 |
203 | while(temp):
204 | num += temp.val * (2**(length-1))
205 | length -= 1
206 | temp = temp.next
207 |
208 | return num
209 |
210 | def nextLargerNodes(self,head):
211 | result = []
212 | temp = head
213 | while(temp):
214 | result.append(temp.val)
215 | temp = temp.next
216 |
217 | stack = []
218 | n = len(result)
219 | i = n-1
220 | while(i >= 0):
221 | next = 0
222 | while(len(stack)!=0 and stack[-1] <= result[i]):
223 | stack.pop()
224 | if(len(stack)!=0 and stack[-1] > result[i]):
225 | next = stack[-1]
226 | stack.append(result[i])
227 | result[i] = next
228 | i-=1
229 | return result
230 | def removeNthNodeFromEnd(self,head,n):
231 | first = head
232 | second = head
233 | for i in range(n):
234 | if(second.next is None):
235 | if(i == n - 1):
236 | self.head = self.head.next
237 | return self.head
238 | second = second.next
239 | while(second.next is not None):
240 | second = second.next
241 | first = first.next
242 |
243 | first.next = first.next.next
244 |
245 | def removeNthNodeFromEnd_hint(self):
246 | message="""
247 | Remove Nth Node from end of a linked list
248 | ------------------------------------
249 | Purpose : to remove the Nth node from end of the linked list
250 | Approach: We use a two pointer approach. The first and second pointer both start by refering to head.
251 | We then move the second pointer by N steps without moving the first pointer.
252 | Now both the pointers have a distance of N nodes between them.
253 | Now, we move both the pointer by a step each until the second pointer reaches the end of linked list.
254 | Since both the pointers will still be at a distacne of N nodes , when the second pointer reaches the end of linked list ,
255 | the first pointer will be at a distance of N nodes from the end i.e at the Nth node from the end.
256 | So we delete the node pointed by the first pointer.
257 |
258 | Edge Case: There are 2 possible edge cases in the above mentioned approach
259 | ---------------------------------------------------
260 | While moving the second pointer by N nodes , we keep checking if the "next" of the second pointer is null
261 | If it is null then 2 cases may arise:
262 | 1) The length of linked list is exactly N and in that case the value of the loop variable i would be N-1
263 | and the Nth node from end would be the head. So in that case we update the head by setting the head to head.next
264 | 2) The length of list is < n :
265 | In this case, since we can't delete the Nth node from the end, we simply return head .
266 |
267 |
268 |
269 | Time Complexity:
270 | --------------------
271 | O(L): where L is the length of the Linked List
272 | """
273 | print(message)
274 |
275 |
276 |
277 |
278 |
279 | # ping = linkedlist()
280 | # ping.append(1)
281 | # ping.append(2)
282 | # ping.printLL()
283 |
--------------------------------------------------------------------------------
/edualgo/Unbounded Knapsack (Rod cutting).py:
--------------------------------------------------------------------------------
1 | # tabulation
2 |
3 | def knapSack(W, wt, val, n):
4 | K = [[0 for x in range(W + 1)] for x in range(n + 1)]
5 |
6 | # Build table K[][] in bottom up manner
7 | for i in range(n + 1):
8 | for w in range(W + 1):
9 | if i == 0 or w == 0:
10 | K[i][w] = 0
11 | elif wt[i-1] <= w:
12 | K[i][w] = max(val[i-1] + K[i][w-wt[i-1]], K[i-1][w]) # K[i] (because we can pick the same item multiple times)
13 | else:
14 | K[i][w] = K[i-1][w]
15 |
16 | return K[n][W]
17 |
18 |
19 | # Driver code
20 | val = [60, 100, 120]
21 | wt = [10, 20, 30]
22 | W = 50
23 | n = len(val)
24 | print(knapSack(W, wt, val, n))
25 |
--------------------------------------------------------------------------------
/edualgo/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'╔{"═" * (width + indent * 2)}╗\n' # upper_border
8 | if title:
9 | box += f'║{space}{title:<{width}}{space}║\n' # title
10 | box += f'║{space}{"-" * len(title):<{width}}{space}║\n' # underscore
11 | box += ''.join([f'║{space}{line:<{width}}{space}║\n' for line in lines])
12 | box += f'╚{"═" * (width + indent * 2)}╝' # lower_border
13 | print(box)
14 |
--------------------------------------------------------------------------------
/edualgo/algorithms/KMP_Pattern_Matching.py:
--------------------------------------------------------------------------------
1 | def calculate_longest_prefix_suffix(pattern, lps):
2 | length = len(pattern)
3 |
4 | lps[0] = 0 #lps of 0th index is always 0
5 |
6 | l = 0
7 | pos = 1
8 | while pos < length:
9 | if pattern[pos] == pattern[l]:
10 | lps[pos] = l + 1
11 | l += 1
12 | pos += 1
13 | else:
14 | if l != 0:
15 | l = lps[l-1]
16 | else:
17 | lps[pos] = 0
18 | pos += 1
19 |
20 | def KMP(pattern, input_str):
21 | '''
22 | Time Complexity: O(N)
23 | '''
24 | flag = 0
25 |
26 | input_len = len(input_str)
27 | pat_len = len(pattern)
28 |
29 | if not pat_len:
30 | return 0
31 |
32 | lps = [0] * pat_len
33 |
34 | # generate lps
35 | calculate_longest_prefix_suffix(pattern, lps)
36 |
37 | i = 0
38 | j = 0
39 | while i < input_len:
40 | if input_str[i] == pattern[j]:
41 | i += 1
42 | j += 1
43 | else:
44 | if j != 0:
45 | j = lps[j-1]
46 | else:
47 | i += 1
48 | if j == pat_len:
49 | print("Match found at index", (i-j))
50 | flag = 1
51 | j = lps[j-1]
52 | if flag == 0:
53 | print("Match not found!!")
54 |
55 |
56 | if __name__ == "__main__":
57 |
58 | input_str = "ABABDABACDABABCABAB"
59 | pattern = "ABABC"
60 |
61 | print("Input string =", input_str)
62 | print("Pattern to be searched =", pattern)
63 |
64 | # Function cal
65 | KMP(pattern, input_str)
66 |
67 |
68 |
--------------------------------------------------------------------------------
/edualgo/algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'_{"_" * (width + indent * 2)}_\n' # upper_border
8 | if title:
9 | box += f'_{space}{title:<{width}}{space}_\n' # title
10 | box += f'_{space}{"-" * len(title):<{width}}{space}_\n' # underscore
11 | box += ''.join([f'_{space}{line:<{width}}{space}_\n' for line in lines])
12 | box += f'_{"_" * (width + indent * 2)}_' # lower_border
13 | print(box)
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/edualgo/algorithms/booyer_moore_voting.py:
--------------------------------------------------------------------------------
1 | '''
2 |
3 | The following file contains the code for Moore majority voting algorithm.
4 | It returns the majority element in an array(i.e element occuring more than n/2 times in the array). It is
5 | also capable of returning the frequency of the majority element.
6 | Incase of no such element, it returns -1
7 |
8 | '''
9 |
10 | class BoyerMooreMajority:
11 |
12 | def __init__(self, array=None):
13 | self.arr = array
14 | self.majority_element = None
15 | self.votes_count = 0
16 |
17 | def get_majority_element(self):
18 | '''
19 | This function returns the majority element present in the array. Incase no such element exists
20 | it returns -1
21 | '''
22 | try:
23 | if self.arr is None:
24 | ve = ValueError()
25 | ve.strerror = "Passed array cannot be None"
26 | raise ve
27 | elif type(self.arr) != list:
28 | ve = ValueError()
29 | ve.strerror = "Please pass an array of elements"
30 | raise ve
31 | elif len(self.arr) == 0:
32 | ve = ValueError()
33 | ve.strerror = "Passed array cannot be empty"
34 | raise ve
35 |
36 | except ValueError as v:
37 | print(f'Value Error : {v.strerror}')
38 |
39 | else:
40 | candidate = None
41 | votes = 0
42 | length = len(self.arr)
43 | for i in range(length):
44 | if votes == 0:
45 | candidate = self.arr[i]
46 | votes = 1
47 | elif self.arr[i] == candidate:
48 | votes += 1
49 | else:
50 | votes -= 1
51 |
52 | for i in range(length):
53 | if self.arr[i] == candidate:
54 | self.votes_count += 1
55 |
56 | if self.votes_count > length // 2:
57 | self.majority_element = candidate
58 | else:
59 | self.majority_element = -1
60 |
61 | return self.majority_element
62 |
63 | def get_vote_count(self):
64 | '''
65 | This function returns the frequency or votes of the majority element. Incase of no majority element
66 | it returns -1
67 | '''
68 | try:
69 | if self.majority_element is None:
70 | raise ValueError
71 | except ValueError as v:
72 | print('Value Error : Please run get_majority_element function properly first.')
73 |
74 | else:
75 | if self.majority_element == -1:
76 | self.votes_count = -1
77 |
78 | return self.votes_count
79 |
80 |
81 | # CALLING CODE EXAMPLE
82 | #arr = [1,2,3,1,1,4,5,1,1,7,1]
83 | #mva = BoyerMooreMajority(arr) # create an object
84 | #mva.get_majority_element() # This returns 1 as output
85 | #mva.get_vote_count() # This returns 6 as output
--------------------------------------------------------------------------------
/edualgo/algorithms/matrices.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 |
3 | def rotateImage(img_arr,n,hint=False):
4 | if(hint is True):
5 | rotateImage_hint()
6 | for layer in range(int(n/2)):
7 | first = layer
8 | last = n-1-layer
9 | for i in range(first,last):
10 | offset = i - first
11 | top = img_arr[first][i]
12 | img_arr[first][i] = img_arr[last - offset][first]
13 | img_arr[last - offset][first] = img_arr[last][last - offset]
14 | img_arr[last][last - offset] = img_arr[i][last]
15 | img_arr[i][last] = top
16 |
17 | def rotateImage_hint():
18 | message = """
19 | Rotate The Image
20 | ------------------------------------
21 |
22 | Purpose :To rotate a N x N 2D array representing an image without
23 | using any external space
24 | Method : 2D array, time-space complexity
25 |
26 | Time Complexity : Worst Case - O(n^2), n = number of rows in a matrix
27 | Space Complexity : O(1)
28 |
29 | Hint :
30 | Try implementing rotation in layers
31 |
32 | Pseudocode :
33 | for layer in range(int(n/2)):
34 | first = layer
35 | last = n-1-layer
36 | for i in range(first,last):
37 | offset = i - first
38 | top = img_arr[first][i]
39 | img_arr[first][i] = img_arr[last - offset][first]
40 | img_arr[last - offset][first] = img_arr[last][last - offset]
41 | img_arr[last][last - offset] = img_arr[i][last]
42 | img_arr[i][last] = top
43 |
44 | Visualization:
45 |
46 | Given image :
47 |
48 | 1 2 3 1 4 1
49 | 4 8 9 ---> 8 8 2
50 | 1 8 9 9 9 3
51 |
52 | Find the pivot (if any) :
53 |
54 | 1 2 3
55 |
56 | +---+
57 | 4 | 8 | 9 ---> 8 is the constant position
58 | +---+
59 |
60 | 1 8 9
61 |
62 |
63 | Rotate Layer Wise using temp variable :
64 |
65 | +---+
66 | 1 | 2 | 3
67 | +---+
68 | +---+ +---+
69 | | 4 | 8 | 9 | -----> rotate the highlighted layer in 90 degree
70 | +---+ +---+
71 | +---+
72 | 1 | 8 | 9
73 | +---+
74 |
75 | Rotate Next layer :
76 |
77 | +---+ +---+
78 | | 1 | 4 | 3 |
79 | +---+ +---+
80 | 8 8 2 -----> rotate the highlighted layer in 90 degree
81 | +---+ +---+
82 | | 1 | 9 | 9 |
83 | +---+ +---+
84 |
85 | Finally you have the desired rotated array.
86 | """
87 | print_msg_box(message)
88 |
89 | def setZeros(matrix,row,column):
90 | row_arr = [False] * row
91 | col_arr = [False] * column
92 | for i in range(row):
93 | for j in range(column):
94 | if(matrix[i][j] == 0):
95 | row_arr[i] = True
96 | col_arr[j] = True
97 |
98 | for i in range(row):
99 | if(row_arr[i]):
100 | for j in range(column):
101 | matrix[i][j] = 0
102 |
103 | for i in range(column):
104 | if(row_arr[i]):
105 | for j in range(row):
106 | matrix[j][i] = 0
107 |
--------------------------------------------------------------------------------
/edualgo/algorithms/prime.py:
--------------------------------------------------------------------------------
1 | def isPrime(n):
2 |
3 | # Corner case
4 | if (n <= 1):
5 | return False
6 |
7 | # Check from 2 to n-1
8 | for i in range(2, n):
9 | if (n % i == 0):
10 | return False
11 |
12 | return True
13 |
14 |
15 | # Driver Code
16 | if isPrime(11):
17 | print("true")
18 | else:
19 | print("false")
20 |
--------------------------------------------------------------------------------
/edualgo/algorithms/segment_tree.py:
--------------------------------------------------------------------------------
1 | class SegmentTree:
2 | def build_tree_hint(self):
3 | message = """
4 | Build Segment Tree
5 | ------------------------------------
6 | Purpose : Building a Segment tree for the given array and query
7 | Method : Recursion
8 |
9 | Time Complexity : Worst Case - O(n)
10 |
11 | Working Hint:
12 | Initialize relevant leaf nodes with array elements, and assign result of the query to the parent node.
13 |
14 | Pseudocode :
15 | --> if array_start_index == array_end_index:
16 | --> Assign the corresponding leaf node the value of array element at array_start_index
17 | --> return leaf node value
18 | --> Find middle element of the array range [array_start_index, array_end_index]
19 | --> Perform query on leaf nodes values and assign result to parent node
20 | --> Return Parent Node Value
21 |
22 | Example:
23 | --> obj = SegmentTree([1,2,3,4,5,6,7], 2, 5) # (2,5) is the range of query to be performed on.
24 | --> obj.build_tree(0,6) # 0 and 6 are starting and ending index of array
25 | """
26 | print(message)
27 |
28 | def get_result_hint(self):
29 | message = """
30 | Get Result of Range Query from Segment Tree
31 | ------------------------------------
32 | Purpose : Building a Segment tree for the given array and query
33 | Method : Recursion
34 |
35 | Time Complexity : Worst Case - O(logn)
36 |
37 | Working Hint:
38 | Reach child nodes for the corresponding range, and return result of the query to the parent node.
39 |
40 | Pseudocode :
41 | --> if array_start_index and array_ending_index are inside query range:
42 | --> return leaf node value
43 | --> if array_start_index or array_ending_index is outside query range:
44 | --> return constant for corresponding function
45 | --> Find middle element of the array range [array_start_index, array_end_index]
46 | --> Perform query on leaf nodes values and return the result
47 |
48 | Example:
49 | --> obj = SegmentTree([1,2,3,4,5,6,7], 2, 5) # (2,5) is the range of query to be performed on.
50 | --> obj.build_tree(0,6) # 0 and 6 are starting and ending index of array
51 | --> obj.get_result(0,6) # 0 and 6 are starting and ending index of array
52 | """
53 | print(message)
54 |
55 | def __init__(self,arr,l,r,function = 'add'):
56 | self.tree = [None for _ in range(3*len(arr))]
57 | self.arr = arr
58 | self.l = l
59 | self.r = r
60 | self._function = ('add', 'min', 'max', 'xor', 'product')
61 | self.func = function
62 |
63 | @property
64 | def get_function_list(self):
65 | """
66 | Get The list of the avaliable functions available to create the segment tree of.
67 |
68 | Returns:
69 | tuple: Tuple of functions
70 | """
71 | return self._function
72 |
73 | def build_tree(self, ss, se, idx = 0):
74 | """
75 | Build the segment tree of the corresponding function.
76 |
77 | Args:
78 | ss ([int]): Starting Index
79 | se ([int]): Ending Index
80 | idx (int, optional): Index of segment tree node. Defaults to 0.
81 | """
82 | if ss==se:
83 | self.tree[idx] = self.arr[ss]
84 | return self.tree[idx]
85 |
86 | mid = (ss + se) // 2
87 |
88 | if self.func == 'add':
89 | self.tree[idx] = self.build_tree(ss, mid, 2*idx+1) + self.build_tree(mid+1, se, 2*idx+2)
90 | elif self.func == 'min':
91 | self.tree[idx] = min(self.build_tree(ss, mid, 2*idx+1), self.build_tree(mid+1, se, 2*idx+2))
92 | elif self.func == 'max':
93 | self.tree[idx] = max(self.build_tree(ss, mid, 2*idx+1), self.build_tree(mid+1, se, 2*idx+2))
94 | elif self.func == 'xor':
95 | self.tree[idx] = self.build_tree(ss, mid, 2*idx+1) ^ self.build_tree(mid+1, se, 2*idx+2)
96 | elif self.func == 'product':
97 | self.tree[idx] = self.build_tree(ss, mid, 2*idx+1) * self.build_tree(mid+1, se, 2*idx+2)
98 | return self.tree[idx]
99 |
100 | def get_result(self, ss, se, idx = 0):
101 | """[
102 | Args:
103 | ss ([int]): Starting Index
104 | se ([int]): Ending Index
105 | idx (int, optional): Index of segment tree node. Defaults to 0.
106 |
107 | Returns:
108 | int/float: Result for the given range
109 | """
110 | if ss >= self.l and se <= self.r:
111 | return self.tree[idx]
112 |
113 | if se < self.l or ss > self.r:
114 | if self.func == 'add':
115 | return 0
116 | elif self.func == 'min':
117 | return 10**9
118 | elif self.func == 'max':
119 | return -10**9
120 | elif self.func == 'xor':
121 | return 0
122 | elif self.func == 'product':
123 | return 1
124 |
125 | mid = (ss + se) // 2
126 | if self.func == 'add':
127 | return self.get_result(ss,mid,2*idx+1) + self.get_result(mid+1,se,2*idx+2)
128 | elif self.func == 'min':
129 | return min(self.get_result(ss,mid,2*idx+1), self.get_result(mid+1,se,2*idx+2))
130 | elif self.func == 'max':
131 | return max(self.get_result(ss,mid,2*idx+1), self.get_result(mid+1,se,2*idx+2))
132 | elif self.func == 'xor':
133 | return self.get_result(ss,mid,2*idx+1) ^ self.get_result(mid+1,se,2*idx+2)
134 | elif self.func == 'product':
135 | return self.get_result(ss,mid,2*idx+1) * self.get_result(mid+1,se,2*idx+2)
136 |
--------------------------------------------------------------------------------
/edualgo/algorithms/sieve_of_eratosthenes.py:
--------------------------------------------------------------------------------
1 | class SieveOfEratosthenes:
2 | def hint_sieve(self):
3 | message = """
4 | Builds Sieve for prime no. less than n
5 | ------------------------------------
6 | Purpose : Building Sieve of Eratosthenes
7 | Method : Simple loops and Sieve building algo
8 |
9 | Time Complexity : O(nlog(logn))
10 |
11 | Working Hint:
12 | Initialize the Sieve and Update the values of factor of the initial primes. For example,
13 | initial the sieve with true values only and starting with 2 if the value at that index is true
14 | then set the value of its factor index(4,6,8,10,...) to false and repeat the process.
15 |
16 | Pseudocode :
17 | --> Intialize the sieve(list) with all true values
18 | --> Set 0 and 1 index as False
19 | --> while k*k <= n:
20 | --> if value at kth index of sieve is true:
21 | --> set value at factor index of k as false
22 |
23 | Example:
24 | --> obj = SieveOfEratosthenes()
25 | --> obj.build_sieve(10)
26 | --> obj.get_prime # get list of prime less than n
27 | --> obj.get_sieve # get sieve that was built
28 | """
29 | print(message)
30 |
31 | def build_sieve(self, n):
32 | """
33 | Builds the sieve.
34 |
35 | Args:
36 | n ([int]): prime numbers less than n
37 | """
38 | self.__sieve = [True for _ in range(n+1)]
39 | self.__sieve[0:2] = (False, False)
40 |
41 | k = 2
42 | while k*k <= n:
43 | if self.__sieve[k]:
44 | for i in range(k*k, n + 1, k):
45 | self.__sieve[i] = False
46 |
47 | k += 1
48 |
49 | @property
50 | def get_prime(self):
51 | """
52 | Builds list of prime no. less than n using sieve
53 |
54 | Returns:
55 | [list]: List of prime no. less than n
56 | """
57 | prime = [k for k,i in enumerate(self.__sieve) if i]
58 | return prime
59 |
60 | @property
61 | def get_sieve(self):
62 | """
63 | Return the sieve built in build_sieve
64 |
65 | Returns:
66 | [list]: Sieve
67 | """
68 | return self.__sieve
--------------------------------------------------------------------------------
/edualgo/algorithms/stack_seq_finder.py:
--------------------------------------------------------------------------------
1 | def stack_sequence(pushes , pops):
2 | """Stack Sequence Finder using python"""
3 | stack = []
4 | sequence = []
5 | i = 0
6 | j = 0
7 | for n in pushes:
8 | stack.append(n)
9 | sequence.append(f"Push[{n}]")
10 | j += 1
11 | while j and stack[-1] == pops[i]:
12 | sequence.append(f"Pop[{stack.pop()}]")
13 | i += 1
14 | j -= 1
15 | return sequence
16 |
17 |
18 | if __name__ == "__main__":
19 | pushesin = list(map(int , input().split()))
20 | popsin = list(map(int , input().split()))
21 | output = stack_sequence(pushesin , popsin)
22 | if len(output) == 2*len(pushesin):
23 | print("")
24 | for sequnce in output:
25 | print(sequnce , end=" ")
26 | else:
27 | print("The sequences isn't valid\n")
28 |
--------------------------------------------------------------------------------
/edualgo/backtracking_algorithms/Knight’s_tour.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | def isSafe(n, x, y, board): # function to check if x,y are valid indexes
5 | if(x >= 0 and y >= 0 and x < n and y < n and board[x][y] == -1):
6 | return True
7 | return False
8 |
9 | def printSolution(n, board): # function to print Chessboard matrix
10 | print('Result: ')
11 | for i in range(n):
12 | for j in range(n):
13 | print(board[i][j], end=" ")
14 | print()
15 |
16 | # function solves the Knight Tour problem using Backtracking.
17 | def knightTour(n, hint=False):
18 | start = time.time()
19 | if hint:
20 | knight_tour_hint()
21 | end = time.time()
22 | # Initialization of Chess Board matrix
23 | board = [[-1 for i in range(n)]for i in range(n)]
24 |
25 | # move_x and move_y define next move of Knight.
26 | move_x = [2, 1, -1, -2, -2, -1, 1, 2] # move_x is for next value of x
27 | move_y = [1, 2, 2, 1, -1, -2, -2, -1] # move_y is for next value of y
28 |
29 | board[0][0] = 0 # Initially Knight at the first block
30 | pos = 1 # Step counter for knight's position
31 |
32 | # Checking if solution exists or not
33 | if(not knightTourUtil(n, board, 0, 0, move_x, move_y, pos)):
34 | print("Solution does not exist")
35 | else:
36 | printSolution(n, board)
37 | print("Time Taken: ", end-start)
38 |
39 | def knightTourUtil(n, board, curr_x, curr_y, move_x, move_y, pos):
40 | if(pos == n**2):
41 | return True
42 |
43 | # Try all next moves from the current coordinate x, y
44 | for i in range(8):
45 | new_x = curr_x + move_x[i]
46 | new_y = curr_y + move_y[i]
47 | if(isSafe(n, new_x, new_y, board)):
48 | board[new_x][new_y] = pos
49 | if(knightTourUtil(n, board, new_x, new_y, move_x, move_y, pos+1)):
50 | return True
51 | board[new_x][new_y] = -1 # Backtracking
52 | return False
53 |
54 | def knight_tour_hint():
55 | message = """
56 | The Knight's Tour Problem
57 | -------------------------------------------------------------
58 | Purpose : Given a N*N Chess board with the Knight placed
59 | on the first block of an empty board. Our task is to move
60 | according to the rules of chess knight must visit each
61 | square exactly once. Print the order of each the cell in
62 | which they are visited.
63 |
64 | Method: Backtracking, Recursion
65 | Time Complexity: O(8^(N*N))
66 |
67 | Hint:
68 | We choose a move of the knight from all the moves
69 | available, and then recursively check if this will lead
70 | us to the solution or not. If not, then we will backtrack
71 | and choose a different path.
72 |
73 | Pseudocode:
74 | A Knight can make maximum eight moves.
75 |
76 | +-------+-------+-------+-------+-------+
77 | | | (i-2, | | (i-2, | |
78 | | | j-1) | | j+1) | |
79 | +-------+-------+-------+-------+-------+
80 | | (i-1, | | | | (i-1, |
81 | | j-2) | | | | j+2) |
82 | +-------+-------+-------+-------+-------+
83 | | | | (i,j) | | |
84 | | | | | | |
85 | +-------+-------+-------+-------+-------+
86 | | (i+1, | | | | (i+1, |
87 | | j-2) | | | | j+2) |
88 | +-------+-------+-------+-------+-------+
89 | | | (i+2, | | (i+2, | |
90 | | | j-1) | | j+1) | |
91 | +-------+-------+-------+-------+-------+
92 |
93 | 1. Add one of the next moves to solution list and recursively
94 | check if this move leads to a solution.
95 | 2. If the move chosen in the above step doesn't lead to a
96 | solution then remove that move from the solution list and
97 | try other alternative moves.
98 | 3. If none of the moves work then return false.
99 | ("No Soultion Exist")
100 | Else if all the squares are visited "Print the Soultion".
101 |
102 | Visualization:
103 | Suppose we have a Chess Board of 5X5 size as Below:
104 | INPUT: n=5
105 |
106 | Output:
107 | +-----+-----+-----+-----+-----+
108 | | 1 | 14 | 9 | 20 | 3 |
109 | +-----+-----+-----+-----+-----+
110 | | 24 | 19 | 2 | 15 | 10 |
111 | +-----+-----+-----+-----+-----+
112 | | 13 | 8 | 23 | 4 | 21 |
113 | +-----+-----+-----+-----+-----+
114 | | 18 | 25 | 6 | 11 | 16 |
115 | +-----+-----+-----+-----+-----+
116 | | 7 | 2 | 17 | 22 | 5 |
117 | +-----+-----+-----+-----+-----+
118 |
119 | Learn More:
120 | The Knight's Tour Problem -
121 | https://en.wikipedia.org/wiki/Knight%27s_tour
122 |
123 |
124 | """
125 | print_msg_box(message)
126 | # knightTour(8, True)
127 |
--------------------------------------------------------------------------------
/edualgo/backtracking_algorithms/Rat_in_a_Maze.py:
--------------------------------------------------------------------------------
1 | # Rat in a Maze Problme via Backtracking
2 | # the function rat_in_a_maze() takes the maze as an input (as 0 and 1)
3 | # Source :- Top Left
4 | # Destination :- Bottom Right
5 | # Moves allowed is DOWN, UP, LEFT and RIGHT
6 |
7 | from __init__ import print_msg_box
8 | from time import time
9 | import sys
10 | sys.setrecursionlimit(150000)
11 |
12 | def rat_in_a_maze(maze, way=1, hint=False): # Main Function which takes the maze and way as an input
13 | start=time()
14 | if hint:
15 | rat_in_a_maze_hint()
16 |
17 | # By default, 1 is considered as walls and 0 is considered as way
18 | n=len(maze);m=len(maze[0]) # Dimentions of the maze
19 | wall= way^1
20 | direction=[[1,0,'D'],[0,1,'R'],[-1,0,'U'],[0,-1,'L']] # Directions to move
21 | visited=[[0]*m for i in range(n)] # To maintain the already visited spot
22 |
23 | # Base Condition to check whether the source or destination contains a wall
24 | if wall in (maze[0][0], maze[n-1][m-1]):
25 | return 'Not Possible'
26 |
27 | temp=move_rat(0,0, n, m, maze, visited,way,direction,[])
28 | ans="".join(temp[1]) if temp[0] else 'Not Possible'
29 | print("Time Taken := ", time()-start)
30 | return ans
31 |
32 | def move_rat(xx, yy, n, m, maze, visited,way, direction,ans):
33 | visited[xx][yy]=1
34 | # If the rat reached the destination
35 | if(xx == n-1 and yy == m-1):
36 | return [1,ans]
37 |
38 | for i in range(4):
39 | row = xx + direction[i][0]
40 | col = yy + direction[i][1]
41 | if(0<=row for Row the isRowSafe function will check whether any digit in this row is equal to the digit that we are going to place are equal
84 | if yes then return false else continue and return true at last.
85 | -> for Column the isColSafe function will check whether any digit in this Column is equal to the digit that we are going to place are equal
86 | if yes then return false else continue and return true at last.
87 | -> for Box that is the box that are of fixed size of 3 X 3, the function isBoxSafe is used and do the same as above
88 | But one thing the start of row and column are important that is calculated using :
89 | rs = row - row%3
90 | cs = col - col%3
91 | * Now if we are unable to place the digit then we try the next digit and continue the process...
92 | and if we are able to place the digit then we will Recursively call the Sudoku_Solver() function ,if this call return true then
93 | we will continue else we have to Backtrack by placing 0 to that cell and try another number in that place...
94 |
95 | Visualization:
96 | suppose we have a sudoku of 4 X 4 size as Below:
97 | INPUT:
98 | 0 1 2 3
99 | +---------------+
100 | 0 |1 3 |0 4|
101 | | | |
102 | 1 |2 0 |3 1|
103 | |-------+-------|
104 | 2 |0 1|0 2|
105 | | | |
106 | 3 |4 0|1 0|
107 | +---------------+
108 |
109 | 0 -> Empty Cell
110 |
111 | we found the first Empty cell (0,2).
112 | Now we will check numbers from [1-9].
113 | we find that we can place a 2.
114 |
115 | 0 1 2 3
116 | +---------------+
117 | 0 |1 3 |2 4|
118 | | | |
119 | 1 |2 0 |3 1|
120 | |-------+-------|
121 | 2 |0 1|0 2|
122 | | | |
123 | 3 |4 0|1 0|
124 | +---------------+
125 | Now Recursively finding the Empty cell
126 | we found (1,1) and the Recursion continue
127 |
128 | 0 1 2 3
129 | +---------------+
130 | 0 |1 3 |2 4|
131 | | | |
132 | 1 |2 4 |3 1|
133 | |-------+-------|
134 | 2 |0 1|0 2|
135 | | | |
136 | 3 |4 0|1 0|
137 | +---------------+
138 |
139 | 0 1 2 3
140 | +---------------+
141 | 0 |1 3 |2 4|
142 | | | |
143 | 1 |2 4 |3 1|
144 | |-------+-------|
145 | 2 |3 1|4 2|
146 | | | |
147 | 3 |4 2|1 0|
148 | +---------------+
149 |
150 | FINAL RESULT:
151 | 0 1 2 3
152 | +---------------+
153 | 0 |1 3 |2 4|
154 | | | |
155 | 1 |2 4 |3 1|
156 | |-------+-------|
157 | 2 |3 1|4 2|
158 | | | |
159 | 3 |4 2|1 3|
160 | +---------------+
161 |
162 | """
163 | print_msg_box(message)
164 |
--------------------------------------------------------------------------------
/edualgo/backtracking_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'╔{"═" * (width + indent * 2)}╗\n' # upper_border
8 | if title:
9 | box += f'║{space}{title:<{width}}{space}║\n' # title
10 | box += f'║{space}{"-" * len(title):<{width}}{space}║\n' # underscore
11 | box += ''.join([f'║{space}{line:<{width}}{space}║\n' for line in lines])
12 | box += f'╚{"═" * (width + indent * 2)}╝' # lower_border
13 | print(box)
14 |
--------------------------------------------------------------------------------
/edualgo/backtracking_algorithms/m_coloring_problem.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | class Graph():
5 |
6 | def __init__(self, vertices):
7 | self.V = vertices
8 | self.graph = [[0 for column in range(vertices)]for row in range(vertices)]
9 |
10 | def isSafe(self, v, colour, c):
11 | for i in range(self.V):
12 | if self.graph[v][i] == 1 and colour[i] == c:
13 | return False
14 | return True
15 |
16 | def graphColourUtil(self, m, colour, v):
17 | if v == self.V:
18 | return True
19 |
20 | for c in range(1, m + 1):
21 | if self.isSafe(v, colour, c) is True:
22 | colour[v] = c
23 | if self.graphColourUtil(m, colour, v + 1) is True:
24 | return True
25 | colour[v] = 0
26 |
27 | def graphColouring(self, m):
28 | colour = [0] * self.V
29 | if self.graphColourUtil(m, colour, 0) is None:
30 | return "Not Possible"
31 |
32 | return ' '.join(list(map(str,colour)))
33 |
34 | def m_coloring(graph,m,hint=False):
35 | start = time.time() # start time
36 | if hint:
37 | m_coloring_hint()
38 | g = Graph(len(graph))
39 | g.graph = graph # 2D graph matrix
40 | m = m # m colors
41 | result = g.graphColouring(m)
42 | end = time.time() # end time
43 | print("Time Taken: ",end-start)
44 | return result
45 |
46 |
47 | def m_coloring_hint():
48 | message="""
49 | M Coloring Problem
50 | ------------------------------------------------------------------------------------------
51 | Purpose : Given an undirected graph and a number m, determine if the graph can be colored with
52 | at most m colors such that no two adjacent vertices of the graph are colored with same color.
53 |
54 | Method : Backtracking
55 |
56 | Time Complexity : O(m^V)
57 | Space Complexity : O(V)
58 |
59 | Hint :
60 | The idea is to assign colors one by one to different vertices, starting from the vertex 0.
61 | Before assigning a color, we check for safety by considering already assigned colors to the adjacent vertices.
62 | If we find a color assignment which is safe, we mark the color assignment as part of solution.
63 | If we do not a find color due to clashes then we backtrack and return false.
64 |
65 | Pseudocode:
66 | Begin
67 | if all vertices are checked, then
68 | return true
69 | for all colors col from available colors, do
70 | if isValid(vertex, color, col), then
71 | add col to the colorList for vertex
72 | if graphColoring(colors, colorList, vertex+1) = true, then
73 | return true
74 | remove color for vertex
75 | done
76 | return false
77 | End
78 |
79 | Visualization:
80 | Input:
81 | 2D Graph: [[0, 1, 1, 1], [1, 0, 1, 0], [1, 1, 0, 1], [1, 0, 1, 0]]
82 | m color: 3
83 |
84 | Input Graph Representaion:
85 | (D)---(C)
86 | | / |
87 | | / |
88 | | / |
89 | (A)---(B)
90 |
91 | Solution: yes, it is 3 colorable
92 | (2)---(3)
93 | | / |
94 | | / |
95 | | / |
96 | (1)---(2)
97 | Output: 1 2 3 2
98 |
99 | Learn More:
100 | - Backtracking - https://en.wikipedia.org/wiki/Backtracking
101 | - Graph_coloring - https://en.wikipedia.org/wiki/Graph_coloring
102 |
103 | """
104 | print_msg_box(message)
105 |
106 |
107 | # print(m_coloring([[0, 1, 1, 1], [1, 0, 1, 0], [1, 1, 0, 1], [1, 0, 1, 0]],3,True))
108 |
109 |
110 |
--------------------------------------------------------------------------------
/edualgo/backtracking_algorithms/n_queen.py:
--------------------------------------------------------------------------------
1 | # N-Queens Problem via Backtracking
2 |
3 | from __init__ import print_msg_box
4 | from time import time as ti
5 |
6 | def n_queens(board_size,hint=False): #Main function argument =size of the board
7 |
8 | st=ti()
9 |
10 | #Occupied Diagonals and Columns
11 | diagonal1={};diagonal2={} #For right and left Diagonal respectively
12 | Col={} #For Column which are already alloted to some queen
13 | ans=place_queen(0,[],board_size,diagonal1,diagonal2,Col)
14 | print("Time Taken := ",ti()-st)
15 |
16 | if hint:
17 | n_queens_hint()
18 |
19 | if not ans:
20 | return -1
21 |
22 |
23 | return ans
24 |
25 | def place_queen(row,a,n,diagonal1,diagonal2,Col): #Recursive Function to check and place the queens
26 | #If the answer is found, row will be equal to the size of the board i.e. n
27 | if(row==n):
28 | return a
29 | R=row+1
30 |
31 | for C in range(1,n+1):
32 |
33 | #Check that particular Column is free to place a queen or not
34 | if((C not in Col) and ((R+C) not in diagonal1) and ((R-C) not in diagonal2)):
35 |
36 | #Add the Column and their respective Diagonals to the dictionary to mark they are Occupied
37 | Col[C]=0
38 | diagonal1[R+C]=0;diagonal2[R-C]=0
39 | chk=place_queen(row+1,a+[(row,C-1)],n,diagonal1,diagonal2,Col)
40 | if chk: #If the answer is found, Stop the recursion
41 | return chk
42 |
43 | #Deleaating the Column and Diagonals to vacant that place
44 | del diagonal1[R+C];del Col[C]
45 | del diagonal2[R-C]
46 |
47 | return False
48 |
49 | def n_queens_hint():
50 | message="""
51 | N-Queens problem via Backtracking
52 | ------------------------------------------------------------------------------------------
53 |
54 | Purpose : To place n queens in an n X n Chessboard where no queen attack another queen
55 | in any form(such as diagonaly, through row or through Column), i.e. all the queen
56 | place are safe.
57 |
58 | Method : Backtracking
59 | Time Complexity :
60 | Worst Case - O(n!)
61 | Best Case - O(n^2)
62 |
63 | Hint : Since we can put only one queen in a particular row/column, we can assume the
64 | board to be a 1-d array where the index number of the array is the row number
65 | and the value in that position is the column of the placed Queen. We must also
66 | maintain seprate set for left and right diagonals. Then we can sequentially put
67 | the queen in every column of the given row and check wether the postition is right or
68 | not and recursively do so for the next row. If the recursion fails, we can backtrack
69 | and try a diffrent column and repeat the process.
70 |
71 | Pseudocode:
72 | --> Input: board_size
73 | 1) Maintain a set of occupied Diagonals and Columns
74 | diagonal1={};diagonal2={}
75 | Col={}
76 | ans=[]
77 | 2) Call the recursive function for row=0
78 | 3) In the Function,for a given row=R, try every Column C between 0 to n-1:
79 | Check if the Column is occupied and the respective diagonal (R-C) and
80 | (R+C) are occupied or not.
81 | If free, then add the column C and the Diagonals in their respective
82 | sets and call the recursive function for next row, i.r row=R+1
83 |
84 | If not free, then try another column.
85 | 4) If in the recursive function, row= board_size. That means all the queens are placed
86 | and now we can stop the recursion.
87 |
88 | Visualization:
89 | --> board_size = 3
90 | For R=0,
91 | placing queen at C=0 i.e at (0,0)
92 | +-------+-------+-------+
93 | | | | |
94 | | X | | |
95 | | | | |
96 | +-------+-------+-------+
97 | | | | |
98 | | | | |
99 | | | | |
100 | +-------+-------+-------+
101 | | | | |
102 | | | | |
103 | | | | |
104 | +-------+-------+-------+
105 | For R=1,
106 | Placing Queen at C=0, i.e at (1,0)
107 | But, column 0 is already occupied,so try next Col
108 |
109 | Placing Queen at C=1, i.e at (1,1)
110 | But, Diagonal2(R+C) i.e. 0 is already occupied
111 |
112 | Placing Queen at C=2, i.e. at (1,2)
113 | +-------+-------+-------+
114 | | | | |
115 | | X | | |
116 | | | | |
117 | +-------+-------+-------+
118 | | | | |
119 | | | | X |
120 | | | | |
121 | +-------+-------+-------+
122 | | | | |
123 | | | | |
124 | | | | |
125 | +-------+-------+-------+
126 | Queen is safe
127 | For R=2
128 | Placing Queen at C=0, i.e at (2,0)
129 | +-------+-------+-------+
130 | | | | |
131 | | X | | |
132 | | | | |
133 | +-------+-------+-------+
134 | | | | |
135 | | | | X |
136 | | | | |
137 | +-------+-------+-------+
138 | | | | |
139 | | X | | |
140 | | | | |
141 | +-------+-------+-------+
142 | But, column 0 is already occupied,so try next Col
143 |
144 | Placing Queen at C=1, i.e.at (2,1)
145 | But, Diagonal1(R-C) i.e 1 already exist,
146 | Placing Queen at C=2, i.e at (2,2)
147 | But, column 2 is already occupied,so try next Col
148 | Placing Queen at C=3, but thats out of the board
149 | Hence recursion fails
150 |
151 | We back track to R=1, and place the queen in next Col
152 |
153 | And this will go On but there in no solution for a board of
154 | size 3, Hence the program will return -1.
155 |
156 | But for a board_size =4, the following will be one of the answer,
157 | [(0, 1), (1, 3), (2, 0), (3, 2)]
158 |
159 | +-------+-------+-------+-------+
160 | | | | | |
161 | | | X | | |
162 | | | | | |
163 | +---------------+-------+-------+
164 | | | | | |
165 | | | | | X |
166 | | | | | |
167 | +-------+-------+-------+-------+
168 | | | | | |
169 | | X | | | |
170 | | | | | |
171 | +-------+-------+-------+-------+
172 | | | | | |
173 | | | | X | |
174 | | | | | |
175 | +-------+-------+-------+-------+
176 |
177 | """
178 | print_msg_box(message)
179 | #print(n_queens(4))
--------------------------------------------------------------------------------
/edualgo/backtracking_algorithms/print_all_permutations_of_a_given_string.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | def permute(lst, l, r):
5 | if l==r:
6 | solution = ''.join(lst)
7 | if solution not in result: #if characters in the strings are not duplicate
8 | total_permutations[0]+=1
9 | result.append(''.join(lst))
10 | else:
11 | for i in range(l,r+1):
12 | lst[l], lst[i] = lst[i], lst[l] #Swap
13 | permute(lst,l+1,r) # Calling Recursive Function
14 | lst[l], lst[i] = lst[i], lst[l] # backtrack
15 |
16 | result = [] # Storing total permutations of a string
17 | total_permutations = [0] # Count total permutations
18 | def string_permutaions(string,hint=False):
19 | start = time.time()
20 | if hint:
21 | string_permutaions_hint()
22 | n = len(string)
23 | lst = list(string) #covert string to list
24 | permute(lst,0,n-1)
25 | end = time.time()
26 | print("Time Taken: ",end-start)
27 | print("Total Permutations: ",total_permutations)
28 | return result
29 |
30 | def string_permutaions_hint():
31 | message="""
32 | Print All Permutations Of A Given String
33 | ------------------------------------------------------------------------------------------
34 | Purpose : In this problem, we are given a string. Our task is to print all permutations
35 | of a given string.
36 | Method : Backtracking
37 |
38 | Time Complexity : O(n*n!)
39 |
40 | Hint :
41 | Apply Backtracking to find permutations of a given string.
42 |
43 | Pseudocode:
44 | 1. Define a string.
45 | 2. Fix a character and swap the rest of the characters.
46 | 3. Call the recursive function for rest of the characters.
47 | 4. Backtrack and swap the characters again.
48 |
49 | Visualization:
50 | Recursion Tree for Permutations of String "ABC"
51 | * represents fixed characters
52 | +---+---+---+
53 | | A | B | C |
54 | +---+---+---+
55 | |
56 | --------------------------------------------------------------------
57 | swap A,A | swap A,B | swap A,C |
58 | +---+---+---+ +---+---+---+ +---+---+---+
59 | |*A | B | C | |*B | A | C | |*C | B | A |
60 | +---+---+---+ +---+---+---+ +---+---+---+
61 | A fixed | B fixed | C fixed |
62 | --------------------- --------------------- ---------------------
63 | swap B,B | swap B,C | swap A,A | swap A,C | swap B,B | swap B,A |
64 | +---+---+---+ +---+---+---+ +---+---+---+ +---+---+---+ +---+---+---+ +---+---+---+
65 | |*A |*B | C | |*A |*C | B | |*B |*A | C | |*B |*C | A | |*C |*B | A | |*C |*A | B |
66 | +---+---+---+ +---+---+---+ +---+---+---+ +---+---+---+ +---+---+---+ +---+---+---+
67 | AB fixed AC fixed BA fixed BC fixed CB fixed CA fixed
68 |
69 | FINAL RESULT = ABC, ACB, BAC, BCA, CBA, CAB
70 |
71 | Learn More:
72 | - Backtracking - https://en.wikipedia.org/wiki/Backtracking
73 | - Permutations - https://en.wikipedia.org/wiki/Permutation
74 |
75 | """
76 | print_msg_box(message)
77 |
78 | # print(string_permutaions("ABCA",True))
79 |
--------------------------------------------------------------------------------
/edualgo/binSearchAlgo.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 |
3 | class BinarySearyAlgorithm:
4 |
5 | #Define the bsearch method i.e. binary search
6 | def bsearch(self, list, val):
7 |
8 | list_size = len(list) - 1
9 |
10 | low = 0 #lower index
11 | high = list_size
12 |
13 | # Find the middle most value
14 |
15 | while low <= high:
16 | mid = (low + high)// 2 #divide
17 |
18 | if list[mid] == val:
19 | return mid
20 | # Compare the value the middle most value
21 | if val > list[mid]:
22 | low = mid + 1
23 | else:
24 | high = mid - 1
25 | # Value isn't found anywhere in the list, then return none
26 | if low > high:
27 | return None
28 |
29 | def print_bsearch_hint(self):
30 | message = """
31 | FIND AN ELEMENT FROM A GIVEN SORTED LIST USING BINARY SEARCH ALGORITHM AND PRINT THE ELEMENT'S POSITION
32 | -+-+-+-
33 | In binary search we take a sorted list of elements and start looking for an element at the middle of the list.
34 | If the search value matches with the middle value in the list we complete the search.
35 | Otherwise we eleminate half of the list of elements by choosing whether to procees with the right or left half
36 | of the list depending on the value of the item searched. This is possible as the list is sorted and it is
37 | much quicker than linear search. Here we divide the given list and conquer by choosing the proper half of the
38 | list. We repeat this approcah till we find the element or conclude about it's absence in the list.
39 | -+-+-+-
40 | PSEUDOCODE:
41 | 1. Compare 'x' with the middle element
42 | 2. If x matches with the middle most element, we return the index of the middle element i.e. 'mid'.
43 | 3. Else if x is greater than the middle element, x will lie in the right sub-part of the list from the middle element.Thus, we recur the right part of the list.
44 | 4. Else, the x is smaller than the middle element, so we recur the left sub-part of the list.
45 | -+-+-+-
46 | TIME COMPLEXITY OF BINARY SEARCH ALGORITHM:
47 |
48 | Worst-case performance: O(log n)
49 | Best-case performance: O(1)
50 | Average performance: O(log n)
51 | Worst-case space complexity: O(1)
52 | -+-+-+-
53 | MORE INFO HERE: https://en.wikipedia.org/wiki/Binary_search_algorithm
54 | """
55 | print_msg_box(message)
56 |
57 | # Initialize the sorted list
58 |
59 | #list = [2,7,19,34,53,72] #samplelist
60 |
61 | # Print the search result
62 | #obj1 = BinarySearyAlgorithm()
63 | #print(obj1.bsearch(list,72))
64 | #print(bsearch(list,100))
65 | #print(obj1.print_bsearch_hint())
66 |
--------------------------------------------------------------------------------
/edualgo/circular-linked-list.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | class Node:
3 |
4 | def __init__(self, dataValue=None):
5 | self.dataValue = dataValue
6 | self.next = None
7 |
8 | class singleLinkedList:
9 |
10 | def __init__(self):
11 | self.headValue = None
12 | self.temp = None
13 |
14 | def insertLast(self, *elements):
15 |
16 | for data in elements:
17 |
18 | if self.headValue is None:
19 | self.headValue = Node(data)
20 | self.temp = self.headValue
21 | else:
22 | self.temp.next = Node(data)
23 | self.temp = self.temp.next
24 | self.temp.next = self.headValue
25 | pass
26 |
27 | def insertFirst(self, *elements):
28 |
29 | if self.headValue is not None:
30 | prevheadValue = self.headValue
31 | self.headValue = None
32 | else:
33 | prevheadValue = None
34 |
35 | for data in elements:
36 |
37 | if self.headValue is None:
38 | self.headValue = Node(data)
39 | self.temp = self.headValue
40 | else:
41 | self.temp.next = Node(data)
42 | self.temp = self.temp.next
43 |
44 | if prevheadValue is not None:
45 | self.temp.next = prevheadValue
46 | self.temp = self.temp.next
47 | while self.temp.next != prevheadValue:
48 | self.temp = self.temp.next
49 | self.temp.next = self.headValue
50 |
51 |
52 | def insertMiddle(self, arg1: "data", arg2: "position"):
53 | node = self.headValue
54 | for i in range(1,arg2-1):
55 | if node.next is None:
56 | return
57 | node = node.next
58 | prev = node.next
59 | node.next = Node(arg1)
60 | node = node.next
61 | node.next = prev
62 | while node.next != self.headValue:
63 | node = node.next
64 | node.next = self.headValue
65 |
66 | def delete(self, position: "Position to be deleted"):
67 | #[data|next] --> [data|next] --> [data|next] --> [data|next]
68 | # ^_______________^
69 | node = self.headValue
70 | for i in range(position-2):
71 | node = node.next
72 | node.next = node.next.next
73 | while node.next != self.headValue:
74 | node = node.next
75 | node.next = self.headValue
76 |
77 | def display(self):
78 |
79 | printValue = self.headValue
80 |
81 | if printValue is None:
82 | print("list is empty")
83 |
84 | while printValue is not None:
85 | print (printValue.dataValue)
86 | printValue = printValue.next
87 | pass
88 | def hint(self):
89 | message=""""
90 | Create a node class to have two variables
91 | 1. Store data (datavalue)
92 | 2. Next data address in last it is usually null in circular (next)
93 | linked list
94 | Create another class to perform manipulation in list
95 |
96 | Insert First:
97 | *To insert first element we need to have the data to whether any
98 | data exist before if so then we have to store it safely
99 | * Storing the data in headval
100 | * Taking previous value to set next value of another node
101 | * It repeats until it reaches the previous head value
102 | * Setting the last value to head node
103 |
104 | Insert last:
105 | *To insert last element we need to have the data to whether any
106 | data exist before if so then we have to store it safely
107 | * It repeats until it reaches the head value is occurred
108 | * Setting the last node next value to head node
109 |
110 | Insert Middle:
111 | *To insert middle element we need to have the data to whether any
112 | data exist before if so then we have to store it safely
113 | * Taking previous value to set next value of another node
114 | * It repeats until it reaches the previous head value
115 | * Setting the last next value to head node
116 |
117 | Display:
118 | Display will take next value of node repeatedly so the list is
119 | infinite loop
120 |
121 | """
122 | #creating object
123 | #list = singleLinkedList()
124 |
125 | #list.insertLast(50, 60,70)
126 | #list.display()
127 |
128 | '''
129 | It shows the entered things at last
130 |
131 | output:
132 | =======
133 |
134 | 50
135 | 60
136 | 70
137 | 50...
138 | '''
139 |
140 | #list.insertFirst(10,20,30)
141 | #list.display()
142 |
143 | '''
144 | It shows the entered things at first then remaining
145 |
146 | output:
147 | =======
148 |
149 | 10
150 | 20
151 | 30
152 | 50
153 | 60
154 | 70
155 | 10...
156 | '''
157 |
158 | #print(list.insertMiddle.__annotations__)
159 | #list.insertMiddle(40,4)
160 | #list.display()
161 | '''
162 | It shows the inserted element at nth position
163 |
164 | output:
165 | =======
166 |
167 | 10
168 | 20
169 | 30
170 | 40
171 | 50
172 | 60
173 | 70
174 | 10...
175 | '''
176 |
177 | #list.delete(6)
178 | #list.display()
179 | '''
180 | It shows the list after deleting it
181 |
182 | output:
183 | =======
184 |
185 | 10
186 | 20
187 | 30
188 | 40
189 | 50
190 | 60
191 | 10...
192 | '''
193 |
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/Fibonacci.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 | def fib(n):
4 | if n == 0:
5 | return 0
6 | elif n == 1:
7 | return 1
8 | else:
9 | return fib(n-1) + fib(n-2)
10 | print([fib(i) for i in range(5)])
11 |
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'╔{"═" * (width + indent * 2)}╗\n' # upper_border
8 | if title:
9 | box += f'║{space}{title:<{width}}{space}║\n' # title
10 | box += f'║{space}{"-" * len(title):<{width}}{space}║\n' # underscore
11 | box += ''.join([f'║{space}{line:<{width}}{space}║\n' for line in lines])
12 | box += f'╚{"═" * (width + indent * 2)}╝' # lower_border
13 | print(box)
14 |
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/climbing_stairs.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | def countWays(n):
5 | res = [0 for x in range(n)]
6 | res[0], res[1] = 1, 1
7 | for i in range(2, n):
8 | res[i] = res[i-1] + res[i-2]
9 | return res[n-1]
10 |
11 |
12 | def climbing_stairs(n,hint=False):
13 | start = time.time()
14 | if hint:
15 | climbing_stairs_hint()
16 | ans = countWays(n+1)
17 | end = time.time()
18 | print("Time Taken: ",end-start)
19 | return ans
20 |
21 |
22 | def climbing_stairs_hint():
23 | message= """
24 | Climb Stairs
25 | ------------------------------------------------------------------------------------------
26 | Purpose : There are n stairs, a person standing at the bottom and wants to reach the top.
27 | The person can climb either 1 stair or 2 stairs at a time. Count the number of ways,
28 | the person can reach the top.
29 | Method : Dynamic Programming
30 | Time Complexity : O(m*n)
31 | Space Complexity : O(n)
32 | Hint : Apply Dynamic Programming in bottom up manner.
33 |
34 | Pseudocode:
35 | Create a res[] table in bottom up manner using the following relation:
36 | res[i] = res[i] + res[i-j] for every (i-j) >= 0
37 | such that the ith index of the array will contain
38 | the number of ways required to reach the ith step considering
39 | all the possibilities of climbing (i.e. from 1 to i).
40 |
41 | Visualization:
42 | Input: n=3
43 |
44 | ^ ^ ^
45 | ------- ------- -------
46 | ^ | | ^ |
47 | ------ ------ ------
48 | ^ | ^ | |
49 | ------ ------ ------
50 | ^ | ^ | ^ |
51 | ------ ------- -------
52 |
53 | Output: 3
54 |
55 | Learn More:
56 | - - Dynamic Programming - https://en.wikipedia.org/wiki/Dynamic_programming
57 |
58 | """
59 | print_msg_box(message)
60 |
61 | # print(climbing_stairs(3,True))
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/coin_change.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | def coin_change(coins, amount,hint=False):
5 | start = time.time()
6 | if hint:
7 | coin_change_hint()
8 | dp = [0]*(amount+1)
9 | for i in range(1, amount+1):
10 | if i in coins:
11 | dp[i] = 1
12 | continue
13 | min_coins = float("inf")
14 | for coin in coins:
15 | if i-coin >= 0:
16 | min_coins = min(dp[i-coin], min_coins)
17 |
18 | dp[i] = min_coins+1
19 | end = time.time()
20 | print("Time Taken: ",end-start)
21 |
22 | if dp[-1] == float("inf"):
23 | return -1
24 | print(dp)
25 | return dp[-1]
26 |
27 | def coin_change_hint():
28 | message="""
29 | Coin Change Problem
30 | ------------------------------------------------------------------------------------------
31 | Purpose : In this problem, We are given coins of different denominations and a total amount of money amount.
32 | Calculate the fewest number of coins that we need to make up that amount. If no combination possible return -1.
33 | m = length of the coins array, n = amount
34 |
35 | Time Complexity : O(mn)
36 | Space Complexity : O(n)
37 |
38 | Hint :
39 | Apply Dynamic Programming on coins array to find the minimum required coins.
40 |
41 | Pseudocode:
42 | dp = [0]*(amount+1)
43 | LOOP (i = 1, amount+1):
44 | if i in coins:
45 | dp[i] = 1
46 | continue
47 | min_coins = INFINITE
48 | LOOP coins array as coin:
49 | if i-coin >= 0:
50 | min_coins = min(dp[i-coin], min_coins)
51 | dp[i] = min_coins+1
52 | return dp[-1]
53 |
54 | Visualization:
55 | coins = [1,2,5]
56 | amount = 6
57 | dp = [0]*(amount+1) = [0]*7
58 | index = [0,1,2,3,4,5,6]
59 | dp = [0,0,0,0,0,0,0]
60 |
61 | Applying recursive formula at each index we get min coins
62 | min_coins = min(dp[index-coin], min_coins)
63 |
64 | * At index 1:
65 | index = [0,1,2,3,4,5,6]
66 | dp = [0,1,0,0,0,0,0]
67 |
68 | * At index 2:
69 | index = [0,1,2,3,4,5,6]
70 | dp = [0,1,1,0,0,0,0]
71 |
72 | * At index 3:
73 | index = [0,1,2,3,4,5,6]
74 | dp = [0,1,1,2,0,0,0]
75 |
76 | * At index 4:
77 | index = [0,1,2,3,4,5,6]
78 | dp = [0,1,1,2,2,0,0]
79 |
80 | * At index 5:
81 | index = [0,1,2,3,4,5,6]
82 | dp = [0,1,1,2,2,1,0]
83 |
84 | * At index 6:
85 | index = [0,1,2,3,4,5,6]
86 | dp = [0,1,1,2,2,1,2]
87 |
88 | FINAL RESULT = dp[-1] = 2
89 |
90 | Learn More:
91 | - Change Making - https://en.wikipedia.org/wiki/Change-making_problem
92 |
93 | """
94 | print_msg_box(message)
95 |
96 | # print(coin_change([1,2,5],6,True))
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/house_robber.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | def house_robber(house,hint=False):
5 | start = time.time()
6 | if hint:
7 | house_robber_hint()
8 | n = len(house)
9 | if n == 0:
10 | return 0
11 | if n == 1:
12 | return house[0]
13 | if n == 2:
14 | return max(house[0],house[1])
15 |
16 | val1 = house[0]
17 | val2 = house[1]
18 | max_val = None
19 |
20 | for i in range(2,n):
21 | max_val = max(house[i]+val1, val2)
22 | val1 = val2
23 | val2 = max_val
24 |
25 | end = time.time()
26 | print("Time Taken: ",end-start)
27 |
28 | return max_val
29 |
30 | def house_robber_hint():
31 | message="""
32 | House Robber Problem
33 | ------------------------------------------------------------------------------------------
34 | Purpose : There are n houses build in a line, each of which contains some value in it.
35 | A thief is going to steal the maximal value of these houses,
36 | but he can’t steal in two adjacent houses because the owner of the stolen houses will
37 | tell his two neighbours left and right side. What is the maximum stolen value?
38 |
39 | Method : Dynamic Programming
40 |
41 | Time Complexity : O(n)
42 | Space Complexity : O(1)
43 |
44 | Hint :
45 | Apply Dynamic Programming on value array of houses to find maximum amount.
46 |
47 | Pseudocode:
48 | house: array of houses which contain some values
49 |
50 | Initialize:
51 | val1 = house[0]
52 | val2 = house[1]
53 |
54 | Loop(i=2,size)
55 | (a) max_val = max(house[i]+val1, val2)
56 | (b) val1 = val2
57 | (b) val2 = max_val
58 |
59 | return max_val
60 |
61 | Visualization:
62 | Input: house = [2,1,1,3]
63 |
64 | val1 = house[0] = 2
65 | val2 = house[1] = 1
66 |
67 | for i=2,
68 | max_val = max(house[i]+val1, val2) = max(1+2,1) = 3
69 | val1 = val2 = 1
70 | val2 = max_val = 3
71 |
72 | for i=3,
73 | max_val = max(house[i]+val1, val2) = max(3+1,3) = 4
74 | val1 = val2 = 3
75 | val2 = max_val = 4
76 |
77 | FINAL RESULT = max_val = 4
78 |
79 | Learn More:
80 | - Dynamic Programming - https://en.wikipedia.org/wiki/Dynamic_programming
81 |
82 | """
83 | print_msg_box(message)
84 |
85 | # print(house_robber([2,1,1,3],True))
86 |
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/kadanes_algorithm.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | def maxSubArraySum(a,size):
5 |
6 | max_so_far =a[0]
7 | curr_max = a[0]
8 |
9 | for i in range(1,size):
10 | curr_max = max(a[i], curr_max + a[i])
11 | max_so_far = max(max_so_far,curr_max)
12 |
13 | return max_so_far
14 |
15 | def kadanes_algorithm(arr,hint=False):
16 | start = time.time()
17 | if hint:
18 | kadanes_algorithm_hint()
19 |
20 | ans = maxSubArraySum(arr,len(arr))
21 | end = time.time()
22 | print("Time Taken: ",end-start)
23 | return ans
24 |
25 | def kadanes_algorithm_hint():
26 | message="""
27 | Kadane’s Algorithm
28 | ------------------------------------------------------------------------------------------
29 | Purpose : In this problem, we are given an array. Our task is to find out the maximum subarray sum.
30 | Method : Dynamic Programming
31 |
32 | Time Complexity : O(n)
33 | Space Complexity : O(1)
34 |
35 | Hint :
36 | Apply Dynamic Programming on contiguous array to find max contiguous sum.
37 |
38 | Pseudocode:
39 | Initialize:
40 | max_so_far = a[0]
41 | curr_max = a[0]
42 |
43 | Loop(i=1,size)
44 | (a) curr_max = max(a[i],curr_max + a[i])
45 | (b) max_so_far = max(max_so_far,curr_max)
46 |
47 | return max_so_far
48 |
49 | Visualization:
50 | Input: [-2,1,2,-1]
51 | max_so_far = -2
52 | curr_max = -2
53 |
54 | for i=1, a[0] = -2
55 | curr_max = max(1,-2+1) = 1
56 | max_so_far = max(-2,1) = 1
57 |
58 | for i=2,
59 | curr_max = max(2,1+2) = 3
60 | max_so_far = max(1,3) = 3
61 |
62 | for i=3,
63 | curr_max = max(-1,3-1) = 2
64 | max_so_far = max(3,2) = 3
65 |
66 | FINAL RESULT = max_so_far = 3
67 |
68 | Learn More:
69 | - Maximum Subarray Problem - https://en.wikipedia.org/wiki/Maximum_subarray_problem
70 |
71 | """
72 | print_msg_box(message)
73 |
74 | # print(kadanes_algorithm([-2,1,2,-1],True))
75 |
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/knapsack.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 |
5 | def maximum_weight(W, wt, val, n):
6 | K = [[0 for x in range(W + 1)] for x in range(n + 1)]
7 |
8 | for i in range(n + 1):
9 | for w in range(W + 1):
10 | if i == 0 or w == 0:
11 | K[i][w] = 0
12 | elif wt[i-1] <= w:
13 | K[i][w] = max(val[i-1]
14 | + K[i-1][w-wt[i-1]],
15 | K[i-1][w])
16 | else:
17 | K[i][w] = K[i-1][w]
18 |
19 | return K[n][W]
20 |
21 |
22 | def knapSack(W, wt, val, hint=False):
23 | start = time.time()
24 | if hint:
25 | knapsack_hint()
26 | n = len(val)
27 | ans = maximum_weight(W, wt, val, n)
28 | end = time.time()
29 | print("Time Taken: ", end-start)
30 | return ans
31 |
32 |
33 | def knapsack_hint():
34 | message = """
35 | Knapsack Problem
36 | ------------------------------------------------------------------------------------------
37 | Purpose : Given weights and values of n items, put these items in a knapsack of
38 | capacity W to get the maximum total value in the knapsack. You cannot break an item,
39 | either pick the complete item or don’t pick it (0-1 property).
40 |
41 | Method : Dynamic Programming
42 |
43 | Time Complexity : O(N*W)
44 |
45 | Space Complexity : O(N*W)
46 |
47 | Hint : Apply Dynamic Programming.
48 |
49 | Pseudocode:
50 | > Create a DP[][] table consider all the possible weights
51 | from ‘1’ to ‘W’ as the columns and weights that can be kept as the rows.
52 | > The state DP[i][j] will denote maximum value of ‘j-weight’ considering
53 | all values from ‘1 to ith’.
54 | > Consider ‘wi’ (weight in ‘ith’ row) we can fill it in all columns
55 | which have ‘weight values > wi’.
56 |
57 | Visualization:
58 |
59 | Input:
60 | Let weight elements = {1, 2, 3}
61 | Let weight values = {10, 15, 40}
62 | Capacity=6
63 |
64 |
65 | 0 1 2 3 4 5 6
66 |
67 | 0 0 0 0 0 0 0 0
68 | 1 0 10 10 10 10 10 10
69 | 2 0 10 15 25 25 25 25
70 | 3 0
71 |
72 | Explanation:
73 | For filling 'weight = 2' we come
74 | across 'j = 3' in which
75 | we take maximum of
76 | (10, 15 + DP[1][3-2]) = 25
77 |
78 | 0 1 2 3 4 5 6
79 |
80 | 0 0 0 0 0 0 0 0
81 | 1 0 10 10 10 10 10 10
82 | 2 0 10 15 25 25 25 25
83 | 3 0 10 15 40 50 55 65
84 |
85 | Explanation:
86 | For filling 'weight=3',
87 | we come across 'j=4' in which
88 | we take maximum of (25, 40 + DP[2][4-3])
89 | = 50
90 |
91 | For filling 'weight=3'
92 | we come across 'j=5' in which
93 | we take maximum of (25, 40 + DP[2][5-3])
94 | = 55
95 |
96 | For filling 'weight=3'
97 | we come across 'j=6' in which
98 | we take maximum of (25, 40 + DP[2][6-3])
99 | = 65
100 |
101 | Output: 65
102 | Learn More:
103 | https://en.wikipedia.org/wiki/Knapsack_problem
104 |
105 | """
106 | print_msg_box(message)
107 |
108 |
109 | val = [10, 15, 40]
110 | wt = [1, 2, 3]
111 | W = 6
112 | print(knapSack(W, wt, val, True))
113 |
--------------------------------------------------------------------------------
/edualgo/dynamic_programming/longest_common_subsequence.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 | import time
3 |
4 | def longest_common_subsequence(X,Y,hint=False):
5 | start = time.time()
6 | if hint:
7 | longest_common_subsequence_hint()
8 | m = len(X)
9 | n = len(Y)
10 | L = [[None]*(n+1) for i in range(m+1)]
11 | for i in range(m+1):
12 | for j in range(n+1):
13 | if i == 0 or j == 0 :
14 | L[i][j] = 0
15 | elif X[i-1] == Y[j-1]:
16 | L[i][j] = L[i-1][j-1]+1
17 | else:
18 | L[i][j] = max(L[i-1][j] , L[i][j-1])
19 | end = time.time()
20 | print("Time Taken: ",end-start)
21 | print(L)
22 | return L[m][n]
23 |
24 | def longest_common_subsequence_hint():
25 | message="""
26 | Longest Common Subsequence
27 | ------------------------------------------------------------------------------------------
28 | Purpose : The longest common subsequence problem is finding the longest sequence which exists in both the given strings.
29 | Method : Dynamic Programming
30 |
31 | Time Complexity : O(mn)
32 | Space Complexity : O(mn)
33 |
34 | Hint :
35 | Apply Dynamic Programming on both the strings to find Longest Common Subsequence.
36 |
37 | Pseudocode:
38 | X and Y are strings
39 | m = len(X)
40 | n = len(Y)
41 | L = [[None]*(n+1) for i in range(m+1)]
42 | for i in range(m+1):
43 | for j in range(n+1):
44 | if i == 0 or j == 0 :
45 | L[i][j] = 0
46 | elif X[i-1] == Y[j-1]:
47 | L[i][j] = L[i-1][j-1]+1
48 | else:
49 | L[i][j] = max(L[i-1][j] , L[i][j-1])
50 | return L[m][n]
51 |
52 | Visualization:
53 | X = "ACDEU"
54 | Y = "ABCDE"
55 |
56 | Applying recursive formula at Longest Common Subsequence 2D Array
57 | if i == 0 or j == 0 :
58 | L[i][j] = 0
59 | elif X[i-1] == Y[j-1]:
60 | L[i][j] = L[i-1][j-1]+1
61 | else:
62 | L[i][j] = max(L[i-1][j] , L[i][j-1])
63 |
64 | LCS * A B C D E
65 | * 0 0 0 0 0 0
66 | A 1 1 1 1 1 1
67 | C 0 1 1 2 2 2
68 | D 0 1 1 2 3 3
69 | E 0 1 1 2 3 4
70 | U 0 1 1 2 3 4
71 |
72 | FINAL RESULT: L[m][n] = L[5][5] = 4
73 |
74 |
75 |
76 | Learn More:
77 | - Maximum Subarray Problem - https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
78 |
79 | """
80 | print_msg_box(message)
81 |
82 | # print(longest_common_subsequence("ACDEU","ABCDE",True))
83 |
--------------------------------------------------------------------------------
/edualgo/graph_algorithms/Dijkstra_algorithms.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 |
3 | import sys
4 |
5 |
6 | def dijkstra_algorithm(graph, hint=False):
7 |
8 | global visited_and_distance
9 |
10 | # Providing the graph
11 |
12 | vertices = []
13 | for x in graph:
14 | vertices.append([int(y) for y in input().split()])
15 |
16 | edges = []
17 | for x in graph:
18 | edges.append([int(y) for y in input().split()])
19 |
20 | # Find which vertex is to be visited next
21 |
22 | to_be_visited()
23 |
24 | num_of_vertices = len(vertices[0])
25 |
26 | visited_and_distance = [[0, 0]]
27 | for i in range(num_of_vertices-1):
28 | visited_and_distance.append([0, sys.maxsize])
29 |
30 | for vertex in range(num_of_vertices):
31 |
32 | # Find next vertex to be visited
33 | to_visit = to_be_visited()
34 | for neighbor_index in range(num_of_vertices):
35 |
36 | # Updating new distances
37 | if vertices[to_visit][neighbor_index] == 1 and \
38 | visited_and_distance[neighbor_index][0] == 0:
39 | new_distance = visited_and_distance[to_visit][1] \
40 | + edges[to_visit][neighbor_index]
41 | if visited_and_distance[neighbor_index][1] > new_distance:
42 | visited_and_distance[neighbor_index][1] = new_distance
43 |
44 | visited_and_distance[to_visit][0] = 1
45 |
46 | i = 0
47 |
48 | # Printing the distance
49 | for distance in visited_and_distance:
50 | print("Distance of ", chr(ord('a') + i),
51 | " from source vertex: ", distance[1])
52 | i = i + 1
53 |
54 |
55 | # Function to Find which vertex is to be visited next
56 |
57 | def to_be_visited(num_of_vertices):
58 | v = -10
59 | for index in range(num_of_vertices):
60 | if visited_and_distance[index][0] == 0 \
61 | and (v < 0 or visited_and_distance[index][1] <= visited_and_distance[v][1]):
62 | v = index
63 | return v
64 |
65 |
66 | def print_Dijkstras_hint(self):
67 | message = """
68 | Dijkstra's algorithm allows us to find the shortest path between any two vertices of a graph.
69 | -+-+-+-+-+-+-+-+-+-+-+-+-+--+-+-+-+-+-+-+-+-+-+-+-+-+--+-+-+-+-+-+-+-+-+-+-+-+-+--+-+-+-+-+-+-+-+-+
70 |
71 | Dijkstra's Algorithm works on the basis that any subpath Point 2 ⇒ Point 4 of the shortest path Point 1 ⇒ Point 4 between vertices Point 1 and Point 4 is also the shortest path between vertices Point 2 and Point 4.
72 | Djikstra used this property in the opposite direction i.e we overestimate the distance of each vertex from the starting vertex. Then we visit each node and its neighbors to find the shortest subpath to those neighbors.
73 | The algorithm uses a greedy approach in the sense that we find the next best solution hoping that the end result is the best solution for the whole problem.
74 | -+-+-+-+-+--+-+-+-+--+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75 |
76 | PseudoCode:
77 |
78 | * We need to take care of the trail distance of each vertex. we will store that in an array of size v, where v is that the number of vertices.
79 |
80 | * We also want to be ready to get the shortest path, not only know the length of the shortest path. For this, we map each vertex to the vertex that last updated its path length.
81 |
82 | * Once the algorithm is over, we will backtrack from the destination vertex to the source vertex to seek out the trail .
83 |
84 | * A minimum priority queue are often wont to efficiently receive the vertex with the smallest amount path distance.
85 |
86 | Code:
87 |
88 | function dijkstra(G, S)
89 | for each vertex V in G
90 | distance[V] <- infinite
91 | previous[V] <- NULL
92 | If V != S, add V to Priority Queue Q
93 | distance[S] <- 0
94 |
95 | while Q IS NOT EMPTY
96 | U <- Extract MIN from Q
97 | for each unvisited neighbour V of U
98 | tempDistance <- distance[U] + edge_weight(U, V)
99 | if tempDistance < distance[V]
100 | distance[V] <- tempDistance
101 | previous[V] <- U
102 | return distance[], previous[]
103 |
104 | -+-+-+-+-+-+-+-+-+-+--+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
105 |
106 | Complexity:
107 |
108 | Time Complexity: O(E Log V)
109 | where, E is the number of edges and V is the number of vertices.
110 |
111 | Space Complexity: O(V)
112 | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
113 |
114 | More Info Here: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
115 | """
116 | print_msg_box(message)
117 |
--------------------------------------------------------------------------------
/edualgo/graph_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'╔{"═" * (width + indent * 2)}╗\n' # upper_border
8 | if title:
9 | box += f'║{space}{title:<{width}}{space}║\n' # title
10 | box += f'║{space}{"-" * len(title):<{width}}{space}║\n' # underscore
11 | box += ''.join([f'║{space}{line:<{width}}{space}║\n' for line in lines])
12 | box += f'╚{"═" * (width + indent * 2)}╝' # lower_border
13 | print(box)
14 |
--------------------------------------------------------------------------------
/edualgo/graph_algorithms/kruskal.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict
2 |
3 | class Graph:
4 |
5 | def __init__(self, vertices):
6 | self.V = vertices
7 | self.graph = []
8 |
9 |
10 | def addEdge(self, u, v, w):
11 | self.graph.append([u, v, w])
12 |
13 | def find(self, parent, i):
14 | if parent[i] == i:
15 | return i
16 | return self.find(parent, parent[i])
17 |
18 | def union(self, parent, rank, x, y):
19 | xroot = self.find(parent, x)
20 | yroot = self.find(parent, y)
21 |
22 | if rank[xroot] < rank[yroot]:
23 | parent[xroot] = yroot
24 | elif rank[xroot] > rank[yroot]:
25 | parent[yroot] = xroot
26 |
27 | else:
28 | parent[yroot] = xroot
29 | rank[xroot] += 1
30 |
31 | def KruskalMST(self):
32 |
33 | result = []
34 |
35 | i = 0
36 |
37 | e = 0
38 |
39 | self.graph = sorted(self.graph,
40 | key=lambda item: item[2])
41 |
42 | parent = []
43 | rank = []
44 |
45 |
46 | for node in range(self.V):
47 | parent.append(node)
48 | rank.append(0)
49 |
50 |
51 | while e < self.V - 1:
52 |
53 |
54 | u, v, w = self.graph[i]
55 | i = i + 1
56 | x = self.find(parent, u)
57 | y = self.find(parent, v)
58 |
59 |
60 | if x != y:
61 | e = e + 1
62 | result.append([u, v, w])
63 | self.union(parent, rank, x, y)
64 |
65 |
66 | minimumCost = 0
67 | print ("Edges in the constructed MST")
68 | for u, v, weight in result:
69 | minimumCost += weight
70 | print("%d -- %d == %d" % (u, v, weight))
71 | print("Minimum Spanning Tree" , minimumCost)
72 |
73 |
74 | g = Graph(4)
75 | g.addEdge(0, 1, 10)
76 | g.addEdge(0, 2, 6)
77 | g.addEdge(0, 3, 5)
78 | g.addEdge(1, 3, 15)
79 | g.addEdge(2, 3, 4)
80 |
81 | # Function call
82 | g.KruskalMST()
83 |
--------------------------------------------------------------------------------
/edualgo/graph_algorithms/prim.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | class Graph():
4 |
5 | def __init__(self, vertices):
6 | self.V = vertices
7 | self.graph = [[0 for column in range(vertices)]
8 | for row in range(vertices)]
9 |
10 | def printMST(self, parent):
11 | print("Edge \tWeight")
12 | for i in range(1, self.V):
13 | print(parent[i], "-", i, "\t", self.graph[i][ parent[i] ])
14 |
15 | def minKey(self, key, mstSet):
16 |
17 | min = sys.maxsize
18 |
19 | for v in range(self.V):
20 | if key[v] < min and mstSet[v] is False:
21 | min = key[v]
22 | min_index = v
23 |
24 | return min_index
25 |
26 | def primMST(self):
27 |
28 | key = [sys.maxsize] * self.V
29 | parent = [None] * self.V
30 | key[0] = 0
31 | mstSet = [False] * self.V
32 |
33 | parent[0] = -1
34 |
35 | for cout in range(self.V):
36 | u = self.minKey(key, mstSet)
37 | mstSet[u] = True
38 | for v in range(self.V):
39 | if self.graph[u][v] > 0 and mstSet[v] is False and key[v] > self.graph[u][v]:
40 | key[v] = self.graph[u][v]
41 | parent[v] = u
42 |
43 | self.printMST(parent)
44 |
45 | g = Graph(5)
46 | g.graph = [ [0, 2, 0, 6, 0],
47 | [2, 0, 3, 8, 5],
48 | [0, 3, 0, 0, 7],
49 | [6, 8, 0, 0, 9],
50 | [0, 5, 7, 9, 0]]
51 |
52 | g.primMST();
53 |
--------------------------------------------------------------------------------
/edualgo/graph_algorithms/tsp.py:
--------------------------------------------------------------------------------
1 | from itertools import permutations
2 | from collections import defaultdict
3 | from edualgo import print_msg_box
4 |
5 | class tsp:
6 |
7 | def __init__(self, graph, start = 0):
8 | self.adj_mat = graph
9 | self.start = start
10 | self.size = len( graph )
11 | self.memo = defaultdict( lambda: defaultdict( lambda:float('inf') ) )
12 | self.__min_cost_value = self.__path = None
13 |
14 | # initializing table with optimal answer for every sub__paths of length 1
15 | for i in range(self.size):
16 | if i != self.start:
17 | # optimal distance when i is the end node and start and i are visited
18 | self.memo[i][ 1<>i)&1)==0
49 |
50 | def __get_combinations(self, r):
51 | num = '0'*(self.size-r) + '1'*r
52 | for perm in set(permutations(num)):
53 | yield int(''.join(perm), 2)
54 |
55 | @property
56 | def minimum_cost(self):
57 | if self.__min_cost_value: return self.__min_cost_value
58 |
59 | end_state = (1< lets understand how we will calculate the answer for all subpaths.
118 | i> we have answer to all subpaths of length 1.
119 | ii> starting from 2, we generate all possible subpaths of length 2 to N which also includes the start node.
120 | i> we remove any node (except SOURCE) say NEXT from this set.
121 | ii> form the remaining nodes we will select any node except SOURCE, say END, this end will be the end node for all subpaths of length 1 less than current subpath length.
122 | i> we then attach our NEXT to this subpath.
123 | ii> if this end is giving reduced cost with END ,we keep it.
124 |
125 | B> finding the minimum cost.
126 | we iterate through all the costs of subpaths containing all nodes, the subpath which gives minimum cost value on connecting END to SOURCE is the answer.
127 |
128 | C> finding the actual path.
129 | i> we initialise LAST as SOURCE and VISITED containing all nodes.
130 | do untill we get all nodes:
131 | i> we find a node with min cost to connect to LAST.
132 | ii> set LAST to this node and remove it from VISITED.
133 |
134 | in this way we keep reducing the size of tour getting an optimal node in each step.
135 |
136 | The overall time complexity is O(N^2 * 2^N) and space complexity is O(N* 2^N).
137 |
138 | USAGE
139 | -----
140 |
141 | tsp_obj = tsp(adjacency_matrix, source_node)
142 | # node numbering is expected to start from 0.
143 | # a complete graph is expected.
144 | # adjacency_matrix must be (N*N) where N is the number of nodes.
145 |
146 | minimum_cost = tsp_obj.minimum_cost
147 | # returns an integer, the minimum_cost of tour.
148 |
149 | optimal_tour = tsp_obj.optimal_tour
150 | # returns a list of integers of size N+1, the optimal path.
151 |
152 | """
153 | print_msg_box(message)
--------------------------------------------------------------------------------
/edualgo/greedy_algorithms/Minimum_Product_Subset.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 |
3 | #Minimun product subset of an array
4 |
5 | def min_product_subset(array, hint=False):
6 |
7 | n = len(array) # length of the array
8 | print(array)
9 |
10 | int_neg = 0
11 | int_pos = 0
12 | int_zero = 0
13 | max_neg = float('-inf')
14 | min_pos = float('inf')
15 | prod = 1
16 |
17 | if n == 1:
18 | print(array[0])
19 |
20 | for i in range(0, n):
21 | # counting number of zero
22 | if array[i] == 0:
23 | int_zero = int_zero + 1
24 | continue
25 |
26 | # counting number of negative numbers
27 | if array[i] < 0:
28 | int_neg = int_neg + 1
29 | max_neg = max(max_neg, array[i])
30 |
31 | # counting number of positive numbers
32 | if array[i] > 0:
33 | int_pos = int_pos + 1
34 | min_pos = min(min_pos, array[i])
35 |
36 | prod = prod * array[i]
37 |
38 | if int_zero == n or (int_neg == 0 and int_zero > 0):
39 | print(0)
40 |
41 | if int_neg == 0:
42 | print(min_pos)
43 |
44 | if int_neg % 2 == 0:
45 | prod = int(prod / max_neg)
46 | print(prod)
47 |
48 | if(hint is True):
49 | min_product_subset_hint()
50 | return prod
51 |
52 |
53 | def min_product_subset_hint():
54 | message = """
55 | Minimum Product Subset of an Array
56 | ----------------------------------------------
57 |
58 | Purpose : Finding the minimum product of the subset ,from the following
59 | subsets of an array
60 | Method :
61 | Time Complexity : Worst Case - 0(n)
62 |
63 | Hint : Finding the least product obtained among all the subsets of the given array
64 | Given an array a, we have to find minimum product possible with the subset
65 | of elements present in the array. The minimum product can be single element
66 | also.
67 |
68 | Pseudocode:
69 | -->Input: Set[], set_size
70 | 1. Get the size of power set
71 | power_set_size = pow(2, set_size)
72 | min_product = INT
73 | 2 Loop for counter from 0 to pow_set_size
74 | (a) Loop for i = 0 to set_size
75 | (i) Initialize product_temp to 1
76 | (ii) If ith bit in counter is set
77 | Print ith element from set for this subset
78 | Update product_temp by multiplying with ith element
79 | (iii) Set max_product to min(min_product, product_temp)
80 | (b) Print separator for subsets i.e., newline
81 |
82 | Visualization:
83 |
84 | Input Array :
85 |
86 | +----+----+----+----+----+
87 | | -1 | -1 | -2 | 4 | 3 |
88 | +----+----+----+----+----+
89 |
90 | Step-1: Check if the length of the array = 1
91 | Yes --> Minimum sum product = arr[0]
92 | No --> Push to Step-2
93 |
94 | Step-2: Initializing
95 | int_neg = 0(No.of negative numbers in array)
96 | int_pos = 0(No.of positive numbers in array)
97 | int_zero = 0(No.of zeroes in array), max_neg = float('-inf'),min_pos = float('inf'),
98 | prod = 1(initial product of subset)
99 |
100 | Initializing i = 0 :
101 | int_neg = 1, max_neg = -1,product = 1*(-1) = -1
102 | Initializing i = 1 :
103 | int_neg = 2, max_neg = -1,product = (-1)*(-1) = 1
104 | Initializing i = 2 :
105 | int_neg = 3, max_neg = -2,product = 1*(-2) = -2
106 | Initializing i = 3 :
107 | int_pos = 1, min_pos = 4,product = (-2)*4 = -8
108 | Initializing i = 4 :
109 | int_pos = 2, min_pos = 3,product = (-8)*4 = -24
110 |
111 | Step-3:
112 | a) Check If there are all zeros or no negative number present :
113 | Yes --> Minimum sum product = 0
114 | No --> Go to (b)
115 | b) Check If there are all positive :
116 | Yes --> Minimum sum product = min_pos
117 | No --> Go to (c)
118 | c) Check If there are even number of negative numbers :
119 | Yes --> Minimum sum product = Product/max_neg
120 | No --> Minimum sum product = product
121 |
122 | Step-4:
123 | Prepare the output as "-24"
124 |
125 | """
126 | print_msg_box(message)
127 |
--------------------------------------------------------------------------------
/edualgo/greedy_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'╔{"═" * (width + indent * 2)}╗\n' # upper_border
8 | if title:
9 | box += f'║{space}{title:<{width}}{space}║\n' # title
10 | box += f'║{space}{"-" * len(title):<{width}}{space}║\n' # underscore
11 | box += ''.join([f'║{space}{line:<{width}}{space}║\n' for line in lines])
12 | box += f'╚{"═" * (width + indent * 2)}╝' # lower_border
13 | print(box)
14 |
15 |
16 |
--------------------------------------------------------------------------------
/edualgo/heap.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 |
3 | class Heap:
4 | """
5 | A heap is a specialized tree-based data structure which is essentially
6 | an almost complete tree that satisfies the heap property: the key of P
7 | is less than or equal to the key of C.[2] The node at the "top" of the
8 | heap (with no parents) is called the root node.
9 |
10 | Main feature of this list based Heap is
11 | * is_empty: Check if the heap is empty
12 | * add: Addition of an element in the heap
13 | * pop: Popping the root element of the heap
14 | * update: Update an element with a new value in the heap
15 | * root: get the root element of the heap
16 | * print: print the heap elements.
17 |
18 | Usage:
19 | >>> from heap import Heap
20 |
21 | >>> sample_heap = Heap([2,6,4,8,5,9,2,10])ter
22 | >>> sample_heap.isEmpty()
23 | False
24 | >>> sample_heap.root()
25 | 2
26 | >>> sample_heap.add(15)
27 | >>> sample_heap.add(7)
28 | >>> sample_heap.root()
29 | 2
30 | >>> sample_heap.pop()
31 | 2
32 | >>> sample_heap.add(19)
33 | >>> sample_heap.update(2, 1)
34 | >>> sample_heap.root()
35 | 1
36 | >>> sample_heap.print()
37 | 1, 5, 4, 8, 6, 9, 7, 10, 15, 19
38 | >>> sample_heap.update(8, 11)
39 | >>> sample_heap.add(20)
40 | >>> sample_heap.pop()
41 | 1
42 | >>> sample_heap.update(3, 2)
43 | Traceback (most recent call last):
44 | ...
45 | Exception: The Element 3 is not present in the heap
46 | >>> sample_heap.pop()
47 | 4
48 | >>> sample_heap.add(1)
49 | >>> sample_heap.pop()
50 | 1
51 | >>> for i in range(sample_heap.__len__()):
52 | ... sample_heap.pop()
53 | 5
54 | 6
55 | 7
56 | 9
57 | 10
58 | 11
59 | 15
60 | 19
61 | 20
62 | >>> sample_heap.isEmpty()
63 | True
64 | >>> sample_heap.root()
65 | Traceback (most recent call last):
66 | ...
67 | Exception: Heap is empty !!! Please add elements to the heap
68 | >>> sample_heap.pop()
69 | Traceback (most recent call last):
70 | ...
71 | Exception: Heap is empty !!! Please add elements to the heap
72 | """
73 |
74 | def __init__(self, items=()):
75 | """Initilise the heap with elements in list items"""
76 | self.heap = [None]
77 | self.rank = {}
78 |
79 | for x in items:
80 | self.add(x)
81 |
82 | def __len__(self):
83 | """Returns the length of the heap"""
84 | return len(self.heap)-1
85 |
86 | def isEmpty(self):
87 | """Returns True if heap is empty and False otherwise"""
88 | return len(self.heap) == 1
89 |
90 | def add(self, x):
91 | """Add element in the heap"""
92 | i = len(self.heap)
93 | self.heap.append(x)
94 | self.rank[x] = i
95 | self.up(i)
96 |
97 | def pop(self):
98 | """Remove the root element of the heap and return its value"""
99 | if self.isEmpty():
100 | raise Exception("Heap is empty !!! Please add elements to the heap")
101 |
102 | root = self.heap[1]
103 | del self.rank[root]
104 | x = self.heap.pop()
105 |
106 | if self:
107 | self.heap[1] = x
108 | self.rank[x] = 1
109 | self.down(1)
110 | return root
111 |
112 | def up(self, i):
113 | """Move the element at index i up to its correct position"""
114 | x = self.heap[i]
115 | while i>1 and x if(root is None) return
178 | --> print(root.value)
179 | --> print(root.left.value)
180 | --> print(root.right.value)
181 | --> make recursion calls,
182 | print_tree(root.left)
183 | print.tree(root.right)
184 |
185 | Visualization:
186 |
187 | Given Heap : [3, 6, 4, 10, 7, 12, 15]
188 |
189 | +-----+
190 | | 3 | <-- root
191 | +-----+
192 | / \\
193 | / \\
194 | +-----+ +-----+
195 | root.left --> | 6 | | 4 | <-- root.right
196 | +-----+ +-----+
197 | / \\ / \\
198 | / \\ / \\
199 | +----+ +-----+ +----+ +----+
200 | | 10 | | 7 | | 12 | | 15 |
201 | +----+ +-----+ +----+ +----+
202 |
203 | Step 1: print root, root.left and root.right
204 | Step 2 : call recursive functions
205 |
206 | Finally The Output :
207 | -------------------------
208 | | 3: L: 6, R: 4, |
209 | | |
210 | | 6: L: 10, R: 7, |
211 | | |
212 | | 4: L: 12 ,R: 15, |
213 | -------------------------
214 |
215 | Learn More:
216 | - Heap - https://en.wikipedia.org/wiki/Heap_(data_structure)
217 | """
218 | print_msg_box(message)
219 |
220 | def print(self):
221 | """Print the current heap"""
222 | print(*self.heap[1:], sep=', ')
223 |
224 | if __name__ == "__main__":
225 | import doctest
226 | doctest.testmod()
227 |
228 |
--------------------------------------------------------------------------------
/edualgo/maths/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'╔{"═" * (width + indent * 2)}╗\n' # upper_border
8 | if title:
9 | box += f'║{space}{title:<{width}}{space}║\n' # title
10 | box += f'║{space}{"-" * len(title):<{width}}{space}║\n' # underscore
11 | box += ''.join([f'║{space}{line:<{width}}{space}║\n' for line in lines])
12 | box += f'╚{"═" * (width + indent * 2)}╝' # lower_border
13 | print(box)
14 |
--------------------------------------------------------------------------------
/edualgo/maths/combinatorial.py:
--------------------------------------------------------------------------------
1 | from edualgo import print_msg_box
2 |
3 | class combinationsDict(dict):
4 |
5 | def __missing__(self, k):
6 | n,r = k
7 | if r==0 or r==n:
8 | self[k] = 1
9 | return 1
10 | K = self[n-1,r-1] + self[n-1,r]
11 | self[k]= K
12 | return K
13 |
14 | @property
15 | def hint(self):
16 | message = """
17 |
18 | ------formal definition------
19 | number of combinations is defined as:
20 | The number of selections of a given number of elements from a larger number without regard to their arrangement.
21 |
22 | for r elements to be selected from n elements, number of combinations is denoted by nCr
23 |
24 | nCr = (n!)/((r!)*(n-r)!)
25 |
26 | ------recursive definition------
27 | C(n, r) = C(n-1, r-1) + C(n-1, r)
28 | base case: C(n, 0) = C(n, n) = 1
29 |
30 | ------usage------
31 | obj = combinationsDict()
32 | print("3C2 =",obj[3,2])
33 |
34 | """
35 | print_msg_box(message)
36 |
--------------------------------------------------------------------------------
/edualgo/maths/fibonacci.py:
--------------------------------------------------------------------------------
1 | from __init__ import print_msg_box
2 |
3 | class fib_class:
4 |
5 | def __init__(self, num, hint=False):
6 | if hint is True:
7 | self.fib_hint()
8 | print([self.fib_cal(i) for i in range(num)])
9 |
10 | def fib_cal(self, num):
11 | if num == 0:
12 | return 0
13 | elif num == 1:
14 | return 1
15 | else:
16 | return self.fib_cal(num-1) + self.fib_cal(num-2)
17 |
18 | def fib_hint(self):
19 | message='''
20 | Conditions to calculate the Fibonacci series:
21 | 1. If num == 0 then Fibonacci should return 0
22 | 2. If num == 1 then Fibonacci should return 1
23 | 3. If num > 0 then add the previous number with current number
24 |
25 | Time Complexity : O(2^n)
26 | Space Complexity : O(1)
27 | Where n is number of number of Fibonacci series
28 | '''
29 | print_msg_box(message)
30 |
31 | def fibonacci(num, hint=False):
32 | fib_class(num, hint)
33 |
--------------------------------------------------------------------------------
/edualgo/maths/modular_arithmetic.py:
--------------------------------------------------------------------------------
1 | from edualgo import print_msg_box
2 | from math import gcd
3 |
4 | def binary_exponentiation(x, y, hint = False):
5 |
6 | # iterative version
7 |
8 | if hint:
9 | print_binary_exponentiaition_hint()
10 |
11 | result = 1
12 | while y>0:
13 |
14 | if y%2 == 1:
15 | result *= x
16 |
17 | y //= 2
18 | x *= x
19 |
20 | return result
21 |
22 | def binary_modular_exponentiation(x, y, mod, hint=False):
23 |
24 | # iterative version
25 |
26 | if hint:
27 | print_binary_exponentiaition_hint()
28 |
29 | result = 1
30 | while y > 0:
31 |
32 | if y%2 == 1:
33 | result = (result*x) % mod
34 |
35 | y //= 2
36 | x = (x*x) % mod
37 |
38 | return result
39 |
40 | def modular_inverse(x, y, hint=False):
41 |
42 | if hint:
43 | modular_inverse_hint()
44 |
45 | try:
46 | assert gcd(x,y)==1
47 | except AssertionError:
48 | raise ValueError(f"{x} and {y} are not co-prime")
49 |
50 | return binary_modular_exponentiation(x, y-2, y)
51 |
52 |
53 | def print_binary_exponentiaition_hint():
54 | message = """
55 | The expression X^Y can be evaluated in log(Y) steps.
56 |
57 | let ANS = X^Y
58 |
59 | if Y is even, we can write :
60 | ANS = (X^2)^(Y ÷ 2)
61 |
62 | that is, we square the base and halve the exponent.
63 |
64 | else if Y is odd :
65 | ANS = ANS*X
66 |
67 | that is, we multiply our ANS once with base so that Y reduces by 1 and becomes even.
68 |
69 | These two steps are executed repeatedly till exponent (Y) is greater than 0.
70 |
71 | We can extend this algorithm for modular exponentiation by simply appending a mod operation to the multiplications.
72 |
73 | The time complexity for this algorithm is O(Log(Y)).
74 | """
75 | print_msg_box(message)
76 |
77 | def modular_inverse_hint():
78 | message = """
79 | the modular inverse for A under mod M is defined as X such that
80 | (A*X)%M=1
81 |
82 | According to Fermats’s little theorem,
83 | X = (A^(M-2))%M , when A and M are co-prime
84 | """
85 | print_msg_box(message)
--------------------------------------------------------------------------------
/edualgo/maths/primes.py:
--------------------------------------------------------------------------------
1 | from edualgo import print_msg_box
2 | from math import sqrt
3 | from edualgo.maths.modular_arithmetic import *
4 | from random import randint
5 | from collections import defaultdict
6 |
7 | def is_prime(x, hint=False):
8 |
9 | if hint: is_prime_hint()
10 |
11 | if x<2: return False
12 | if x==2: return True
13 | if x%2==0: return False
14 |
15 | return all([x%i!=0 for i in range(3, int(sqrt(x))+1, 2)])
16 |
17 | def is_prime_hint():
18 | message = """
19 | conditions for any number X to be prime:
20 | 1. X >= 2
21 | 2. 2 is the only even prime
22 | 3. X must not be divisible by any number in [2, X)
23 | we can optimise this check as follows:
24 | i. we need to check for only odd divisors.
25 | ii. divisors and corresponding quotients are only possible divisors left and they are unique upto sqrt(X).
26 | so we need to check for only odd divisors upto sqrt(X) i.e., from 3 to sqrt(X).
27 | """
28 | print_msg_box(message)
29 |
30 | class prime_factorisation:
31 |
32 | def __init__(self, use_sieve=True, sieve_range = int(1e6)):
33 | self.use_sieve = use_sieve
34 | self.sieve_range = sieve_range
35 | if use_sieve:
36 | spf = list(range(self.sieve_range + 1))
37 | for i in range(4, self.sieve_range+1,2):
38 | spf[i] = 2
39 | for i in range(3, int(sqrt(self.sieve_range))+1):
40 | if spf[i] == i:
41 | for j in range(i*i, self.sieve_range+1, i):
42 | if spf[j] == j:
43 | spf[j] = i
44 | self.spf = spf
45 |
46 | def factorise(self, x):
47 | if self.use_sieve and x<=self.sieve_range:
48 | return self.__factorise_fast(x)
49 | else:
50 | factors = defaultdict(int)
51 | while x%2==0:
52 | factors[2] += 1
53 | x >>= 2
54 |
55 | for i in range(3, int(sqrt(x))+1, 2):
56 | while x%i == 0:
57 | factors[i] += 1
58 | x //= i
59 |
60 | if x>2: factors[x] += 1
61 |
62 | return dict(factors)
63 |
64 | def __factorise_fast(self, x):
65 | factors = defaultdict(int)
66 | while x != 1:
67 | factors[self.spf[x]] += 1
68 | x //= self.spf[x]
69 | return dict(factors)
70 |
71 | @property
72 | def hint(self):
73 | message = """
74 |
75 | finding prime factorisation of N
76 |
77 | ----simple factorisation----
78 | 1. while N is even keep dividing N by 2 and keep adding 2 to the answer list.
79 | 2. Now that N is odd, do the following:
80 | i. run loop for i from 3 to sqrt(N) with step size 2 (taking all odd numbers).
81 | i. while i divides N, add i to asnwer list and divide N by i.
82 | 3. if N is still not 1 then its a prime, add it to the answer list.
83 |
84 | The time complexity is O(sqrt(N).log(N))
85 |
86 | ----factorisation using sieve----
87 | simple method is very slow if we have to process multiple factorisation queries.
88 | the idea is to store the smallest prime divisor of every number then use this value to find the factorisation using recursive division.
89 |
90 | 1. creating the smallest prime divisor array:
91 |
92 | pseudo code:
93 | divisor_array = [ 0, 1, 2, 3, 4, 5, ....., N ]
94 |
95 | loop for i from 4 to N with step size of 2:
96 | divisor_array[i] = 2
97 |
98 | loop for i from 3 to sqrt(N):
99 | if divisor_array[i] is i (means i is Prime):
100 | loop for j from i*i to N with step size of i:
101 | if divisor_array[j] == j:
102 | divisor_array[j] = i
103 |
104 | the time complexity is O(N.log(log(N)))
105 | needs O(N) extra space
106 |
107 | 2. finding the factorisation of X
108 |
109 | pseudo code:
110 | factors = []
111 | while X != 1:
112 | factors.append(divisor_array[X])
113 | X = X / divisor_array[X]
114 |
115 | the time complexity is O(log(N))
116 |
117 | """
118 | print_msg_box(message)
119 |
120 | class sieve_of_eratosthenes:
121 |
122 | def __init__(self, n=int(1e6)):
123 |
124 | mark = [True]*(n+1)
125 | mark[0] = mark[1] = False
126 | for i in range(2, int(sqrt(n)) +1):
127 | if mark[i]:
128 | for j in range(i*i, n+1, i):
129 | mark[j] = False
130 |
131 | self.range = n
132 | self.mark = mark
133 |
134 | def is_prime(self, arg):
135 | try:
136 | assert arg<=self.range
137 | except AssertionError:
138 | raise ValueError(f"{arg} > {self.range}")
139 |
140 | return self.mark[arg]
141 |
142 | def filter_primes(self, array):
143 | try:
144 | assert all([x<=self.range for x in array])
145 | except AssertionError:
146 | raise ValueError(f"please make sure the numbers are <= {self.range}")
147 |
148 | return list(filter(lambda x: self.mark[x], array))
149 |
150 | @property
151 | def hint():
152 | message = """
153 | it is used to find primes in range 2 to N
154 |
155 | sieve of eratosthenes algorithm generates an array in which the value at each index i is a boolean value which tells whether i is a prime number or not.
156 |
157 | we take a boolean array of size N with default True except for index 0 and 1
158 |
159 | the idea is to mark multiples of all primes from 2 to sqrt(N) as False.
160 |
161 | pseudo code:
162 | sieve_array = [ True, True, ..... ]
163 | sieve_array[0] = sieve_array[1] = False
164 |
165 | loop for i from 2 to sqrt(N):
166 | if sieve_array[i] is True (means i is Prime):
167 | loop for j from i*i to N with step size of i:
168 | sieve_array[j] = False
169 |
170 | Now, if any index i in sieve_array is true then it means i is a prime.
171 |
172 | the time complexity is O(N.log(log(N)))
173 | needs O(N) extra space
174 | """
175 | print_msg_box(message)
176 |
177 | def is_prime_big(x, hint = False):
178 |
179 | if hint: is_prime_big_hint()
180 |
181 | def miller(d,n):
182 |
183 | a = 2+randint(1,n-4)
184 |
185 | x= binary_modular_exponentiation(a,d,n)
186 | if x in [1,n-1]: return True
187 |
188 | while d!=n-1:
189 | x=binary_modular_exponentiation(x,2,n)
190 | d<<=1
191 | if x==1: return False
192 | if x==n-1: return True
193 |
194 | return False
195 |
196 | def checkprime(n, k = 4):
197 | if n<=1 or n==4:
198 | return False
199 | if n<=3: return True
200 |
201 | d=n-1
202 | while d%2==0:
203 | d//=2
204 |
205 | for _ in range(k):
206 | if not miller(d,n):
207 | return False
208 | return True
209 |
210 | return checkprime(x)
211 |
212 | def is_prime_big_hint():
213 | message = """
214 | to check primality of very large numbers (order 10^10)
215 |
216 | ------Miller Rabin test--------
217 | checks if a number n is prime
218 | k is a input parameter which measures accuracy of the test
219 | generally k = 4
220 |
221 | compute d & r such that d*(2^r) = n-1
222 |
223 | ------test logic------
224 | randomly choose 'a' in range(2,n-1)
225 | compute x = (a^d)%n
226 | if x in [1, n-1]:
227 | return true
228 | else:
229 | keep squaring (with mod n) x while d!=n-1
230 | d*=2
231 | if (x^2)%n == 1: return False
232 | else if (x^2)%n ==n-1 :return True
233 |
234 | the test logic runs k times to ensure accurate results.
235 |
236 | overall time complexity is O(k.(Log(n))^3)
237 | """
238 | print_msg_box(message)
239 |
--------------------------------------------------------------------------------
/edualgo/queue.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 |
3 | class Queue(object):
4 | """
5 | Queue is an abstract data type used to store
6 | data in first-in-first-out (FIFO) data structure.
7 |
8 | We are going to use list(array) to build the queue
9 |
10 | Main feature of this array based queue is
11 |
12 | * enqueue(Addition of an element at the last index of array)
13 | * dequeue(Popping the element from the first index of the array)
14 | * Finding the length of the queue
15 | * Check is the queue is empty
16 | * get the element at the front of the queue
17 |
18 | Example for application using queue:
19 | 1. Priority queue usages
20 | 2. Any line on reservation counters
21 | 3. etc ...
22 |
23 | Reference:
24 | https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
25 |
26 | Usage:
27 | >>> from queue import Queue
28 |
29 | >>> sample_queue = Queue(5)
30 |
31 | >>> for value in [7,17,367,27,777]:
32 | ... sample_queue.enqueue(value)
33 |
34 | >>> sample_queue.print_queue()
35 | | 7 |
36 | | 17 |
37 | | 367 |
38 | | 27 |
39 | | 777 |
40 |
41 | >>> sample_queue.dequeue()
42 | 7
43 |
44 | >>> sample_queue.print_queue()
45 | | 17 |
46 | | 367 |
47 | | 27 |
48 | | 777 |
49 |
50 | >>> sample_queue.front()
51 | 17
52 |
53 | >>> len(sample_queue)
54 | 4
55 |
56 | >>> sample_queue.enqueue(77)
57 |
58 | >>> sample_queue.print_queue()
59 | | 17 |
60 | | 367 |
61 | | 27 |
62 | | 777 |
63 | | 77 |
64 | >>> sample_queue.enqueue(77777)
65 | Traceback (most recent call last):
66 | ...
67 | Exception: Queue size limit reached maximum
68 |
69 | >>> len(sample_queue)
70 | 5
71 | """
72 | def __init__(self, size = 0):
73 | """ Initilise the queue with size 0 and empty data """
74 | self.data = []
75 | self.size = size
76 |
77 | def __len__(self):
78 | """Returns the length of the queue"""
79 | return len(self.data)
80 |
81 | def is_empty(self):
82 | """Returns boolean True if queue is empty and False if we have some data present"""
83 | return len(self.data) == 0
84 |
85 | def enqueue(self, value):
86 | """Enqueue (append) the value to queue """
87 | if len(self.data) == self.size:
88 | """Current queue list:"""
89 | self.print_queue()
90 | raise Exception("Queue size limit reached maximum")
91 |
92 | self.data.append(value)
93 |
94 | def dequeue(self):
95 | """ The front element is popped from the Queue and value of the element is returned"""
96 | if self.is_empty():
97 | raise Exception("Queue is empty !!! Please add data to the Queue :) ")
98 | else:
99 | return self.data.pop(0)
100 |
101 | def front(self):
102 | """Return the first element present in the queue """
103 | if self.is_empty():
104 | raise Exception("Queue is empty !!! Please add data to the Queue :) ")
105 | else:
106 | return self.data[0]
107 |
108 | def print_hint(self):
109 | """Print the details related to Queue and its implementation"""
110 | print(self.__doc__)
111 |
112 | def print_queue(self):
113 | """ Print the current queue"""
114 | for value in self.data:
115 | element = f'| {value} |'
116 | print(element)
117 |
118 |
119 | if __name__ == "__main__":
120 | import doctest
121 | doctest.testmod()
122 |
--------------------------------------------------------------------------------
/edualgo/radix-sort.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from __init__ import print_msg_box
4 |
5 | def counting_sort(array, unit):
6 | n = len(array)
7 | output = [0]*n
8 | count = [0]*10
9 |
10 | for i in array:
11 | pos = (i/unit)
12 | count[int(pos%10)] +=1
13 |
14 | for i in range(1, 10):
15 | count[i] += count[i-1]
16 |
17 | for i in range(n-1, -1, -1):
18 | pos = (array[i]/unit)
19 | output[count[int(pos%10)]-1] = array[i]
20 | count[int(pos%10)]-=1
21 |
22 | for i in range(n):
23 | array[i] = output[i]
24 |
25 |
26 | def radix_sort(array, hint = False):
27 | start = time.time()
28 | maxval = max(array)
29 | unit = 1
30 | while maxval//unit > 0:
31 | counting_sort(array, unit)
32 | unit*=10
33 | end = time.time()
34 | if (hint is True):
35 | radix_sort_hint()
36 | print("Radix Sort Runtime = {}".format(end - start))
37 | return array
38 |
39 |
40 |
41 | def radix_sort_hint():
42 | message = """
43 | Radix Sort
44 | ------------------------------------
45 | Purpose: Sorting a given array
46 | Method: Distributing, Non Comparing
47 | Time Complexity: Sorts in O(n+k) time when elements are in the range from 1 to k.
48 | Hint:
49 | From the given array, we sort the elements based on the i'th digit by performing counting sort on it until the unit value exceeds the maximum value in the array.
50 | Radix sort uses counting sort as a sub routine to sort elements.
51 |
52 | Pseudocode:
53 | Counting-Sort(A, n, unit)
54 | for j = 1 to d do
55 | int count[10] = {0};
56 | for i = 0 to n do
57 | count[key of ((A[i]/unit)%10) in pass j]++
58 | for k = 1 to 10 do
59 | count[k] = count[k] + count[k-1]
60 | for i = n-1 downto 0 do
61 | result[count[key of ((A[i]/unit)%10)] ] = A[j]
62 | count[key of(((A[i]/unit)%10)]--
63 | for i= n-1 to 0 do
64 | A[i] = result[i]
65 | end for(j)
66 | end func
67 |
68 | Radix-Sort(A)
69 | unit = 1
70 | while unit < max(A)
71 | Counting-Sort(A, unit)
72 | unit*=10
73 |
74 |
75 | Visualization:
76 |
77 | Given Array :
78 | +-----+----+----+----+-----+----+---+----+
79 | | 170 | 45 | 75 | 90 | 802 | 24 | 2 | 66 |
80 | +-----+----+----+----+-----+----+---+----+
81 |
82 | First Iteration (unit = 1):
83 |
84 | +---+---+---+---+---+---+---+---+
85 | | 0 | 5 | 5 | 0 | 2 | 4 | 2 | 6 |
86 | +---+---+---+---+---+---+---+---+
87 |
88 | Count Array
89 | +---+---+---+---+---+---+---+---+---+---+
90 | Count | 2 | 0 | 2 | 0 | 1 | 2 | 1 | 0 | 0 | 0 |
91 | +---+---+---+---+---+---+---+---+---+---+
92 | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
93 |
94 |
95 | Cumilative Count Array
96 | +---+---+---+---+---+---+---+---+---+---+
97 | | 2 | 2 | 4 | 4 | 5 | 7 | 8 | 8 | 8 | 8 |
98 | +---+---+---+---+---+---+---+---+---+---+
99 |
100 | From the first iteration array, we take each value as the index of the cumilative count array and that element provides the position in the result array.
101 | Once it is placed, the value in the cumilative count array, reduces by one.
102 |
103 | Example - First Iteration Array -> Value : 66
104 | Pos = (66/1)
105 | Result[Count[int(Pos%10)]-1] = Result[Count[6]-1] = Result[7] = 66
106 |
107 | Result Array
108 | +---+---+---+---+---+---+---+---+---+----+
109 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 66 |
110 | +---+---+---+---+---+---+---+---+---+----+
111 |
112 | Updated Cumilative Array
113 | +---+---+---+---+---+---+---+---+---+---+
114 | | 2 | 2 | 4 | 4 | 5 | 7 | 8 | 8 | 8 | 7 |
115 | +---+---+---+---+---+---+---+---+---+---+
116 |
117 | Final Result Array after First Iteration
118 | +-----+----+-----+---+----+----+----+----+
119 | | 170 | 90 | 802 | 2 | 24 | 45 | 75 | 66 |
120 | +-----+----+-----+---+----+----+----+----+
121 |
122 |
123 | Second Iteration (unit = 10):
124 |
125 | +---+---+---+---+---+---+---+---+
126 | | 7 | 9 | 0 | 0 | 2 | 4 | 7 | 6 |
127 | +---+---+---+---+---+---+---+---+
128 |
129 | Count Array
130 | +---+---+---+---+---+---+---+---+---+---+
131 | Count | 2 | 0 | 1 | 0 | 1 | 0 | 1 | 2 | 0 | 1 |
132 | +---+---+---+---+---+---+---+---+---+---+
133 | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
134 |
135 |
136 | Cumilative Count Array
137 | +---+---+---+---+---+---+---+---+---+---+
138 | | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 7 | 7 | 8 |
139 | +---+---+---+---+---+---+---+---+---+---+
140 |
141 | Final Result Array after Second Iteration
142 | +-----+---+----+----+----+-----+----+----+
143 | | 802 | 2 | 24 | 45 | 66 | 170 | 75 | 90 |
144 | +-----+---+----+----+----+-----+----+----+
145 |
146 | Third Iteration (unit = 100):
147 |
148 | +---+---+---+---+---+---+---+---+
149 | | 8 | 0 | 0 | 0 | 0 | 1 | 0 | 6 |
150 | +---+---+---+---+---+---+---+---+
151 |
152 | Count Array
153 | +---+---+---+---+---+---+---+---+---+---+
154 | Count | 6 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
155 | +---+---+---+---+---+---+---+---+---+---+
156 | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
157 |
158 |
159 | Cumilative Count Array
160 | +---+---+---+---+---+---+---+---+---+---+
161 | | 6 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 8 | 8 |
162 | +---+---+---+---+---+---+---+---+---+---+
163 |
164 | Final Result Array after Third (And Final) Iteration
165 | +---+----+----+----+----+----+-----+-----+
166 | | 2 | 24 | 45 | 66 | 75 | 90 | 170 | 802 |
167 | +---+----+----+----+----+----+-----+-----+
168 |
169 |
170 | Learn More Here - https://en.wikipedia.org/wiki/Radix_sort
171 | """
172 |
173 | print_msg_box(message)
174 |
175 |
--------------------------------------------------------------------------------
/edualgo/search_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | def print_msg_box(msg, indent=1, width=None, title=None):
2 | """Print message-box with optional title."""
3 | lines = msg.split('\n')
4 | space = " " * indent
5 | if not width:
6 | width = max(map(len, lines))
7 | box = f'╔{"═" * (width + indent * 2)}╗\n' # upper_border
8 | if title:
9 | box += f'║{space}{title:<{width}}{space}║\n' # title
10 | box += f'║{space}{"-" * len(title):<{width}}{space}║\n' # underscore
11 | box += ''.join([f'║{space}{line:<{width}}{space}║\n' for line in lines])
12 | box += f'╚{"═" * (width + indent * 2)}╝' # lower_border
13 | print(box)
14 |
--------------------------------------------------------------------------------
/edualgo/search_algorithms/binary_search.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from __init__ import print_msg_box
4 |
5 |
6 | # binary search algorithm
7 | def binary_search(array, x, hint=False):
8 | # array is sorted
9 | dict1 = {array[i]: i for i in range(len(array))}
10 | array = sorted(array)
11 | flag= -1
12 | start = time.time()
13 | low = 0
14 | high = len(array) - 1
15 | while low <= high and x>=array[low] and x<=array[high]:
16 | if array[low] == x:
17 | flag= low
18 | break
19 |
20 | mid = int(low + high) / 2
21 |
22 | if array[mid] == x:
23 | flag= mid
24 | break
25 |
26 | if array[mid] < x:
27 | low = mid + 1
28 |
29 | else:
30 | high = mid - 1
31 | end = time.time()
32 | if (hint is True):
33 | binary_hint()
34 | print("Binary Runtime = {}".format(end - start))
35 | return dict1[array[flag]]
36 |
37 |
38 | def binary_search_hint():
39 | message = """
40 | Binary Search
41 | ------------------------------------
42 | Purpose : searching a required number in a sorted uniformly distributed array
43 | SORTED ARRAY- Arranged in ascending order
44 | Method : Searching first in the position(index) that has maximum probability of having required element.
45 | Time Complexity: Best case- Ω(1)
46 | Worst case- O(logn)
47 | Hint :
48 | Starting from 0th element of array[] and comparing every element to x search one by one.
49 | Formula used : high+low
50 | Middle position(pos) = int (------------)
51 | 2
52 | where low is the lowest index
53 | high is the highest index
54 | x is the number to be searched
55 | arr[i] is the ith element in the given sorted array
56 | Pseudocode:
57 | while low<=high and array[low]<=array[high]
58 | if array[low]==x
59 | return low
60 | *calculate middle position(pos) with formula above
61 | if array[pos]< x
62 | low = pos+1
63 | else
64 | high = pos-1
65 | Visualization:
66 | Number to search => x=3
67 | Given Array : arr[]
68 | index- 0 1 2 3
69 | +-----+-----+-----+-----+
70 | | 1 | 3 | 4 | 6 |
71 | +-----+-----+-----+-----+
72 | First Iteration :
73 | +-----+-----+-----+-----+ low = 0 high = 3
74 | | 1 | 2 | 3 | 6 | arr[low] = 1 arr[high] = 6
75 | +-----+-----+-----+-----+
76 | pos = int(0+3/2) = 1
77 | =>It will check at arr[pos]==x or not which is not and arr[pos] low = pos+1 = 2
79 | Second Iteration :
80 | +-----+-----+-----+-----+ low = 2 high = 3
81 | | 1 | 3 | 4 | 6 | arr[low] = 3 arr[high] = 6
82 | +-----+-----+-----+-----+
83 | pos = int(2+3/2) = 2
84 | =>It will check at arr[pos]==x which is true
85 | => It will return 2
86 | If no element in the array matched x=3 then it would return -1
87 | Learn More Here - https://www.geeksforgeeks.org/interpolation-search/
88 | """
89 | print_msg_box(message)
90 |
--------------------------------------------------------------------------------
/edualgo/search_algorithms/exponential_search.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from __init__ import print_msg_box
4 |
5 | # binary search algorithm
6 | def binary_search(arr, left, right, search):
7 | if(left > right):
8 | return -1
9 |
10 | mid = (left + right)//2
11 |
12 | if(search == arr[mid]):
13 | return mid
14 | elif(search < arr[mid]):
15 | return binary_search(arr, left, mid - 1, search)
16 | else:
17 | return binary_search(arr, mid + 1, right, search)
18 |
19 | # exponential search algorithm
20 | def exponential_search(arr, n, search, hint=False):
21 | start = time.time()
22 |
23 | if(arr[n-1] right)
59 | return -1
60 |
61 | mid = (left + right)//2
62 |
63 | if(search == arr[mid])
64 | return mid
65 | else if(search < arr[mid])
66 | return binary_search(arr, left, mid - 1, search)
67 | else
68 | return binary_search(arr, mid + 1, right, search)
69 |
70 | # exponential search algorithm
71 | def exponential_search(arr, n, search):
72 | if(arr[n-1] search = 233
84 | Steps to be jumped => bound = 2*bound, where bound = 1 (initially)
85 |
86 | Given Array:
87 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
88 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
89 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
90 |
91 | Calls Exponential Search:
92 | First Iteration (bound = 1):
93 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
94 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
95 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
96 | [checking if bound < 16 and arr[1] < search, which is true so going on the next iteration]
97 |
98 | Second Iteration (bound = 2):
99 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
100 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
101 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
102 | [checking if bound < 16 and arr[2] < search, which is true so going on the next iteration]
103 |
104 | Third Iteration (bound = 4):
105 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
106 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
107 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
108 | [checking if bound < 16 and arr[4] < search, which is true so going on the next iteration]
109 |
110 | Fourth Iteration (bound = 8):
111 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
112 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
113 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
114 | [checking if bound < 16 and arr[8] < search, which is true so going on the next iteration]
115 |
116 | Fifth Iteration (bound = 16):
117 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
118 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
119 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
120 | [checking if bound < 16, which is not true so going to call Binary Search]
121 |
122 | Calls Exponential Search:
123 |
124 | 1st Call:
125 | Values: arr = [21, 34, 55, 89, 144, 233, 377, 610], left = bound//2 = 8, right = min(bound, n) = 16, search = 233
126 |
127 | mid value = 12 (=(left+right)//2)
128 |
129 | +----+----+----+----+-----+-----+-----+-----+
130 | | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
131 | +----+----+----+----+-----+-----+-----+-----+
132 | [checking if arr[mid] == search, which is not true so going to call Binary Search]
133 |
134 | 2nd Call:
135 | Values: arr = [233, 377, 610], left = mid+1 = 13, right = 16, search = 233
136 |
137 | mid value = 14 (=(left+right)//2)
138 |
139 | +-----+-----+
140 | | 233 | 377 |
141 | +-----+-----+
142 | [checking if arr[14] == search, which is not true so going to call Binary Search]
143 |
144 | 3rd Call:
145 | Values: arr = [233, 377, 610], left = 13, right = mid-1 = 13, search = 233
146 |
147 | mid value = 13 (=(left+right)//2)
148 |
149 | +-----+
150 | | 233 |
151 | +-----+
152 | [checking if arr[13] == search, which is true so the search returns location of search in the array.]
153 |
154 | If no element in the array matched search = 233 then it would return "Not found!"
155 |
156 | Learn More Here - https://en.wikipedia.org/wiki/Exponential_search
157 | """
158 | print_msg_box(message)
--------------------------------------------------------------------------------
/edualgo/search_algorithms/interpolation_search.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from __init__ import print_msg_box
4 |
5 |
6 | # interpolation search algorithm
7 | def interpolation_search(array, x, hint=False):
8 | # array is sorted
9 | dict1 = {array[i]: i for i in range(len(array))}
10 | array = sorted(array)
11 | flag= -1
12 | start = time.time()
13 | low = 0
14 | high = len(array) - 1
15 | while low <= high and x>=array[low] and x<=array[high]:
16 | if array[low] == x:
17 | flag= low
18 | break
19 |
20 | probe_pos = low + int(((float(high - low) / (array[high] - array[low])) * (x - array[low])))
21 |
22 | if array[probe_pos] == x:
23 | flag= probe_pos
24 | break
25 |
26 | if array[probe_pos] < x:
27 | low = probe_pos + 1
28 |
29 | else:
30 | high = probe_pos - 1
31 | end = time.time()
32 | if (hint is True):
33 | interpolation_search_hint()
34 | print("Interpolation Search Runtime = {}".format(end - start))
35 | return dict1[array[flag]]
36 |
37 |
38 | def interpolation_search_hint():
39 | message = """
40 | Interpolation Search
41 | ------------------------------------
42 | Purpose : searching a required number in a sorted uniformly distributed array
43 | SORTED ARRAY- Arranged in ascending order
44 | Method : Searching first in the position(index) that has maximum probability of having required element.
45 | Time Complexity: Best case- Ω(log(log(n)))
46 | Worst case- O(n)
47 |
48 | Hint :
49 | Starting from 0th element of array[] and comparing every element to x search one by one.
50 |
51 | Formula used : (high-low)
52 | Probable position(pos) = low + int (--------------------) X (x-arr[low])
53 | (arr[high]-arr[low])
54 |
55 | where low is the lowest index
56 | high is the highest index
57 | x is the number to be searched
58 | arr[i] is the ith element in the given sorted array
59 | Pseudocode:
60 | while low<=high and array[low]<=array[high]
61 | if array[low]==x
62 | return low
63 | *calculate probable position(pos) with formula above
64 | if array[pos]< x
65 | low = pos+1
66 | else
67 | high = pos-1
68 |
69 | Visualization:
70 | Number to search => x=3
71 | Given Array : arr[]
72 |
73 | index- 0 1 2 3
74 | +-----+-----+-----+-----+
75 | | 1 | 3 | 4 | 6 |
76 | +-----+-----+-----+-----+
77 |
78 | First Iteration :
79 | +-----+-----+-----+-----+ low = 0 high = 3
80 | | 1 | 3 | 4 | 6 | arr[low] = 1 arr[high] = 6
81 | +-----+-----+-----+-----+
82 | pos = 0+int((3-0)/(6-1))*(3-1) = 0
83 | =>It will check at arr[pos]==x or not which is not and arr[pos] low = pos+1 = 1
85 |
86 | Second Iteration :
87 | +-----+-----+-----+-----+ low = 1 high = 3
88 | | 1 | 3 | 4 | 6 | arr[low] = 3 arr[high] = 6
89 | +-----+-----+-----+-----+
90 | pos = 1+((3-1)/(6-3))*(3-3) = 1
91 | =>It will check at arr[pos]==x which is true
92 | => It will return 1
93 |
94 | If no element in the array matched x=3 then it would return -1
95 |
96 | Learn More Here - https://www.geeksforgeeks.org/interpolation-search/
97 | """
98 | print_msg_box(message)
99 |
--------------------------------------------------------------------------------
/edualgo/search_algorithms/jump_search.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from __init__ import print_msg_box
4 |
5 | # jump search algorithm
6 | def jump_search(arr, n, search, hint=False):
7 | start = time.time()
8 |
9 | i = 0
10 | loc = -1
11 | step = math.floor(math.sqrt(n))
12 | for i in range(0, n, step-1):
13 | if(arr[i]==search):
14 | loc = i
15 | break
16 | elif(arr[i]search):
19 | j = i
20 | j -= (step-1)
21 | for k in range(j+1, i):
22 | if(arr[k]==search):
23 | loc = k
24 | break
25 |
26 | end = time.time()
27 |
28 | if (hint is True):
29 | jump_search_hint()
30 | print("Jump Search Runtime = {}".format(end - start))
31 |
32 | return loc
33 |
34 |
35 | def jump_search_hint():
36 | message = """
37 | Jump Search
38 | ------------------------------------
39 | Purpose: Searching a required number
40 | Method: Iterating, Comparing
41 | Time Complexity: The optimal size of a block to be jumped is (√n).
42 | This makes the time complexity of Jump Search O(√n).
43 | Hint:
44 | Starting from 0th element of arr[], we comparing fewer elements (than linear search) by jumping ahead by fixed steps.
45 | Pseudocode:
46 | loc = -1
47 | step = math.floor(math.sqrt(n))
48 | for i in range[0,length of array,step to jump]:
49 | if(arr[i]==search)
50 | loc = i
51 | break
52 | else if(arr[i]search)
55 | j = i
56 | j -= (step-1)
57 | for k in range[j+1, i]
58 | if(arr[k]==search)
59 | loc = k
60 | break
61 | if(loc<0):
62 | return "Not found!"
63 | else:
64 | return loc
65 |
66 | Visualization:
67 | Number to Search => search = 233
68 | Steps to be jumped = √n, where n = size of the array = √16 = 4
69 |
70 | Given Array :
71 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
72 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
73 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
74 |
75 | First Iteration (i = 0):
76 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
77 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
78 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
79 | [checking if arr[0] > search, which is not true so going on the next iteration]
80 |
81 | Second Iteration (i = 3):
82 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
83 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
84 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
85 | [checking if arr[3] > search, which is not true so going on the next iteration]
86 |
87 | Third Iteration (i = 6):
88 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
89 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
90 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
91 | [checking if arr[6] > search, which is not true so going on the next iteration]
92 |
93 | Fourth Iteration (i = 9):
94 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
95 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
96 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
97 | [checking if arr[9] > search, which is not true so going on the next iteration]
98 |
99 | Fifth Iteration (i = 12):
100 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
101 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
102 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
103 | [checking if arr[12] > search, which is not true so going on the next iteration]
104 |
105 | Sixth Iteration (i = 15):
106 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
107 | | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 | 233 | 377 | 610 |
108 | +---+---+---+---+---+---+---+----+----+----+----+----+-----+-----+-----+-----+
109 | [checking if arr[15] > search, which is true so we go to for loop as linear search starts from i = 13 and ends at i = 14]
110 |
111 | First Sub - Iteration (j = 13)
112 | +-----+-----+-----+
113 | | 233 | 377 | 610 |
114 | +-----+-----+-----+
115 | [checking if arr[13] == search, which is true so the search returns location of search in the array.]
116 |
117 | If no element in the array matched search = 233 then it would return "Not found!"
118 |
119 | Learn More Here - https://en.wikipedia.org/wiki/Jump_search
120 | """
121 | print_msg_box(message)
122 |
--------------------------------------------------------------------------------
/edualgo/search_algorithms/linear_search.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from __init__ import print_msg_box
4 |
5 | # linear search algorithm
6 | def linear_search(array, x, hint=False):
7 | start = time.time()
8 | flag=-1
9 | for i in range(len(array)):
10 | if array[i] == x:
11 | flag=i
12 | break
13 | end = time.time()
14 | if (hint is True):
15 | linear_search_hint()
16 | print("Linear Search Runtime = {}".format(end - start))
17 | return flag
18 |
19 |
20 | def linear_search_hint():
21 | message = """
22 | Linear Search
23 | ------------------------------------
24 | Purpose : searching a required number
25 | Method : Iterating, Comparing
26 | Time Complexity: Worst Case - O(n)
27 | Hint :
28 | Starting from 0th element of array[] and comparing every element to x search one by one.
29 | Pseudocode:
30 | --> for i in range[0,length of array]
31 | if(array[i]= x)
32 | return i
33 | return "Not found"
34 | Visualization:
35 | Number to search => x=3
36 | Given Array :
37 | +-----+-----+-----+
38 | | 5 | 4 | 3 |
39 | +-----+-----+-----+
40 | First Iteration (i=0):
41 | +-----+-----+-----+
42 | | 5 | 4 | 3 |
43 | +-----+-----+-----+
44 | [checking if 5==x, which is not true so going on the next iteration]
45 | Second Iteration (i=1):
46 | +-----+-----+-----+
47 | | 5 | 4 | 3 |
48 | +-----+-----+-----+
49 | [checking if 4==x, which is not true so going on the next iteration]
50 | Third Iteration (i=2):
51 | +-----+-----+-----+
52 | | 5 | 4 | 3 |
53 | +-----+-----+-----+
54 | [checking if 3==x, which is true so the search returns location of x in the array ]
55 | If no element in the array matched x=3 then it would return -1
56 | Learn More Here - https://en.wikipedia.org/wiki/Linear_search
57 | """
58 | print_msg_box(message)
59 |
--------------------------------------------------------------------------------
/edualgo/stack.py:
--------------------------------------------------------------------------------
1 | from tabulate import tabulate
2 | from .__init__ import print_msg_box
3 |
4 |
5 | class error(Exception):
6 | pass
7 |
8 | class Stack(object):
9 | """
10 | Stack is an abstract data type used to store
11 | data in Last In First Out method (LIFO).
12 |
13 | We are going to use list(array) to build the stack
14 |
15 | Main feature of this array based stack is
16 |
17 | * Insert
18 | * deletion of last element
19 | * Finding the length of the stack
20 | * Check is the stack is empty
21 | * get the element at the top of the stack
22 |
23 | Example for application using stack:
24 | 1. browser fetching the previously used URL using back
25 | and forward button
26 | 2. stack of plates in a restaurant
27 | 3. Validating html file by matching the brackets
28 | 4. etc ...
29 |
30 | Reference:
31 | https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
32 |
33 | Usage:
34 | >>> from stack import Stack
35 |
36 | >>> my_stack = Stack(5)
37 |
38 | >>> for value in [10,1,24,200,1000]:
39 | ... my_stack.push(value)
40 |
41 | >>> my_stack.pretty_print()
42 | |-----:|
43 | | 1000 |
44 | | 200 |
45 | | 24 |
46 | | 1 |
47 | | 10 |
48 |
49 | >>> my_stack.pop()
50 | 1000
51 |
52 | >>> my_stack.pretty_print()
53 | |----:|
54 | | 200 |
55 | | 24 |
56 | | 1 |
57 | | 10 |
58 | >>> my_stack.top()
59 | 200
60 |
61 | >>> len(my_stack)
62 | 4
63 |
64 | >>> my_stack.push(10)
65 | >>> my_stack.push(1)
66 | Traceback (most recent call last):
67 | ...
68 | stack.error: Stack size reached maximum
69 |
70 | >>> len(my_stack)
71 | 5
72 | """
73 |
74 |
75 | def __init__(self, size = 0):
76 | """ Initilise the stack with size 0 and empty data """
77 | self.data = []
78 | self.size = size
79 |
80 | def __len__(self):
81 | """Returns the length of the data"""
82 | return len(self.data)
83 |
84 | def is_empty(self):
85 | """Returns boolean False if the data is not empty else True"""
86 | return len(self.data) == 0
87 |
88 | def push(self, value):
89 | """Append the value to data """
90 | if len(self.data) == self.size:
91 | """print the stack"""
92 | raise error("Stack size reached maximum")
93 |
94 | self.data.append(value)
95 |
96 |
97 | def pop(self):
98 | """ Return value from data as well as delete the value
99 | from data after return"""
100 | if self.is_empty():
101 | raise error("Stack is empty")
102 | else:
103 | return self.data.pop()
104 |
105 | def top(self):
106 | """Return the last pushed value from data """
107 | if self.is_empty():
108 | raise error("Stack is empty")
109 | else:
110 | return self.data[-1]
111 |
112 | def print_hint(self):
113 | """Print the documentation for class stack"""
114 | print(self.__doc__)
115 |
116 | def pretty_print(self):
117 | """ Print the stack """
118 | list_of_list = []
119 | for value in self.data:
120 | list_of_list.append([value])
121 | table_data = list_of_list[::-1]
122 | print(tabulate(table_data, tablefmt="pipe"))
123 |
124 |
125 | if __name__ == "__main__":
126 | import doctest
127 | doctest.testmod()
128 |
--------------------------------------------------------------------------------
/edualgo/strings/merge_string.py:
--------------------------------------------------------------------------------
1 | # Foundational implementation from merge sort
2 | # https://en.wikipedia.org/wiki/Merge_sort
3 | """
4 | Python implementation of how to merge two string
5 | For doctests run following command:
6 | python -m doctest -v merge_string.py
7 | or
8 | python3 -m doctest -v merge_string.py
9 |
10 | For manual testing run:
11 | python merge_string.py
12 | """
13 |
14 |
15 | class StringBuilder(object):
16 | def __init__(self, val: str) -> None:
17 | self.store = [val]
18 |
19 | def __iadd__(self, value):
20 | """appends a character to the sequence"""
21 | self.store.append(value)
22 | return self
23 |
24 | def __str__(self) -> str:
25 | """string representation from the built sequence"""
26 | return "".join(self.store)
27 |
28 |
29 | def merge_string(str_1: str, str_2: str) -> str:
30 | """Merges two string into one
31 | :param str_1 : first input string
32 | :param str_2 : second input string
33 | Examples:
34 | >>> merge_string("abc","def")
35 | 'adbecf'
36 | >>> merge_string("mnin","aso")
37 | 'mansion'
38 | """
39 | if len(str_1) < 0 and len(str_2) < 0:
40 | return ""
41 | if len(str_1) < 0 and len(str_2):
42 | return str_2
43 | if len(str_2) < 0 and len(str_1):
44 | return str_1
45 |
46 | ret = StringBuilder("")
47 | i, j = 0, 0
48 | while i < len(str_1) and j < len(str_2):
49 | if i > j:
50 | ret += str_2[j]
51 | j += 1
52 | continue
53 | ret += str_1[i]
54 | i += 1
55 | while i < len(str_1):
56 | ret += str_1[i]
57 | i += 1
58 |
59 | while j < len(str_2):
60 | ret += str_2[j]
61 | j += 1
62 |
63 | return str(ret)
64 |
65 |
66 | if __name__ == "__main__":
67 | print(merge_string("abc", "def"))
68 | print(merge_string("ae", "f"))
69 | print(merge_string("mnin", "aso"))
70 |
--------------------------------------------------------------------------------
/edualgo/strings/rotate_string.py:
--------------------------------------------------------------------------------
1 | '''
2 | Python implementation to rotate a string
3 |
4 | For manual testing :
5 | python rotate_string.py
6 |
7 | '''
8 |
9 | def rotate_string (sentence, rotation_point) :
10 |
11 | '''
12 | The function rotates the given string clockwise by a certain number of times.
13 | For example :
14 | Suppose the string be 'what's up'.
15 | Let the number of rotations be 3.
16 | The final string will be rotated by 3 times clockwise.
17 | Hence the output becomes ' upwhat's'
18 |
19 | '''
20 |
21 | new_string = ""
22 | if (rotation_point%len(sentence) == 0) :
23 | return sentence
24 | new_string = sentence[len(sentence) - (rotation_point%len(sentence)):] + sentence [:-(rotation_point%len(sentence))]
25 | return (new_string)
26 |
27 | if __name__ == '__main__' :
28 |
29 | print(rotate_string('paranjoy', 10)) # prints oyparanj
30 | print(rotate_string('abcdef', 3)) # prints defabc
31 | print(rotate_string('sometimes', 9)) # prints sometimes
32 |
33 |
--------------------------------------------------------------------------------
/edualgo/strings/subsequences_string.py:
--------------------------------------------------------------------------------
1 | '''
2 | Python implementation to find subsequences of a string
3 |
4 | For manual testing :
5 | python subsequences_string.py
6 |
7 | '''
8 |
9 | '''
10 | Python implementation to find subsequences of a string
11 |
12 | For manual testing :
13 | python subsequences_string.py
14 |
15 | '''
16 |
17 | def subsequences_string_main (word, output) :
18 |
19 | '''
20 | The function prints all the subsequences of a string obtained by deleting zero or more characters of the string without changing the original order.
21 | For example :
22 | Suppose the string be 'this'.
23 | Then the substrings will be this thi ths th tis ti ts t his hi hs h is i s
24 | '''
25 |
26 | if len(word) == 0:
27 | print(output, end=' ')
28 | return
29 |
30 | subsequences_string_main(word[1:], output+word[0])
31 | subsequences_string_main(word[1:], output)
32 |
33 | def subsequences_string (word) :
34 | subsequences_string_main(word, "")
35 |
36 | if __name__ == '__main__' :
37 |
38 | subsequences_string('abcd') # prints abcd abc abd ab acd ac ad a bcd bc bd b cd c d
39 |
--------------------------------------------------------------------------------
/images/Abhijit23.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/images/Abhijit23.jpeg
--------------------------------------------------------------------------------
/images/eduAlgo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edualgo/eduAlgo/793a3075871d2841717fa61709cb17ff9eee8f55/images/eduAlgo.png
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | # reading long description from file
4 | with open('README.md', encoding='utf-8') as file:
5 | long_description = file.read()
6 |
7 |
8 | # specify requirements of your package here
9 | REQUIREMENTS = ['requests', 'tabulate']
10 |
11 | # some more details
12 | CLASSIFIERS = [
13 | 'Development Status :: 3 - Alpha',
14 | 'Intended Audience :: Education',
15 | 'Topic :: Education',
16 | 'License :: OSI Approved :: MIT License',
17 | 'Programming Language :: Python :: 3.7',
18 | ]
19 |
20 | # calling the setup function
21 | setup(name='eduAlgo',
22 | version='1.1.6.3',
23 | description='An educational Algorithmic Library',
24 | long_description=long_description,
25 | long_description_content_type = 'text/markdown',
26 | url='https://github.com/Abhijit2505/eduAlgo',
27 | author='Abhijit Tripathy',
28 | author_email='abhijittripathy99@gmail.com',
29 | license='MIT',
30 | packages=['edualgo'],
31 | classifiers=CLASSIFIERS,
32 | install_requires=REQUIREMENTS,
33 | keywords='algorithms'
34 | )
35 |
--------------------------------------------------------------------------------