├── .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 | [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/eduAlgo/eduAlgo/graphs/commit-activity) 16 | [![PyPI format](https://img.shields.io/pypi/format/eduAlgo.svg)](https://pypi.python.org/pypi/eduAlgo/) 17 | [![GitHub contributors](https://img.shields.io/github/contributors/Abhijit2505/eduAlgo.svg)](https://GitHub.com/eduAlgo/eduAlgo/graphs/contributors/) 18 | 19 | 20 | [![Downloads](https://static.pepy.tech/personalized-badge/edualgo?period=total&units=international_system&left_color=black&right_color=orange&left_text=Downloads)](https://pepy.tech/project/edualgo) 21 | [![Downloads](https://static.pepy.tech/personalized-badge/edualgo?period=month&units=international_system&left_color=black&right_color=orange&left_text=Downloads)](https://pepy.tech/project/edualgo) 22 | [![Downloads](https://static.pepy.tech/personalized-badge/edualgo?period=week&units=international_system&left_color=black&right_color=orange&left_text=Downloads)](https://pepy.tech/project/edualgo) 23 | 24 | [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/built-by-developers.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/made-with-python.svg)](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 | 100 | 104 | 105 | 106 | 110 | 114 | 115 | 116 |
97 |
98 | FOSS Hack - 2020 (12th & 13th September 2020) 99 |
101 |
102 | PyCon - 2020 Devsprint ( 04th & 05th October 2020) 103 |
107 |
108 | Hacktoberfest 2020 (October 2020) 109 |
111 |
112 | Winter of Code - DSC, NSEC 113 |
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 | 135 |

This project is supported by:

136 | 137 | 144 | 151 | 158 | 165 | 172 | 173 |
138 |

139 | 140 | 141 | 142 |

143 |
145 |

146 | 147 | 148 | 149 |

150 |
152 |

153 | 154 | 155 | 156 |

157 |
159 |

160 | 161 | 162 | 163 |

164 |
166 |

167 | 168 | 169 | 170 |

171 |
174 | 175 | ## About The Creator 176 | 177 | 178 | 179 | 182 | 186 | 187 |
180 | 181 | 183 | Abhijit Tripathy
184 | DSA Developer and Python Programmer 185 |
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 | [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/built-by-developers.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/made-with-python.svg)](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 | 94 | 98 | 99 |
92 | 93 | 95 | Abhijit Tripathy
96 | DSA Developer and Python Programmer 97 |
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 | --------------------------------------------------------------------------------