├── docs └── config │ ├── CNAME │ ├── generate_code_stubs.md │ ├── CHANGELOG.md │ ├── question.md │ ├── leetscrape_ts.md │ ├── extract_solution.md │ ├── index.md │ ├── installation.md │ └── questions_list.md ├── example ├── data │ ├── questionBody.pickle │ ├── categories.csv │ ├── topicTags.csv │ ├── companies.csv │ └── questionCategory.csv ├── solutions │ ├── test_q_0009_palindromeNumber.py │ ├── test_q_0485_maxConsecutiveOnes.py │ ├── test_q_1946_largestNumberAfterMutatingSubstring.py │ ├── q_0485_maxConsecutiveOnes.py │ ├── q_0009_palindromeNumber.py │ └── q_1946_largestNumberAfterMutatingSubstring.py ├── mdx │ ├── q_0485_maxConsecutiveOnes.mdx │ ├── q_0009_palindromeNumber.mdx │ └── q_1946_largestNumberAfterMutatingSubstring.mdx └── notebooks │ └── package_usage.ipynb ├── codecov.yml ├── src └── leetscrape │ ├── __init__.py │ ├── _helper.py │ ├── models.py │ ├── utils.py │ ├── _constants.py │ ├── question.py │ ├── scripts.py │ ├── extract_solution.py │ ├── questions_list.py │ └── generate_code_stub.py ├── tests ├── test_questions_list.py ├── test__helper.py ├── test_utils.py ├── test_question.py ├── test_generate_code_stub.py ├── q_0009_palindromeNumber_wo_frontmatter.py ├── q_0009_palindromeNumber.py └── test_extract_solution.py ├── LICENSE ├── .github └── workflows │ └── pytest-and-docs.yml ├── pyproject.toml ├── mkdocs.yml ├── .gitignore └── README.md /docs/config/CNAME: -------------------------------------------------------------------------------- 1 | leetscrape.nikhilravi.com -------------------------------------------------------------------------------- /example/data/questionBody.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikhil-ravi/LeetScrape/HEAD/example/data/questionBody.pickle -------------------------------------------------------------------------------- /example/data/categories.csv: -------------------------------------------------------------------------------- 1 | slug,name 2 | algorithms,Algorithms 3 | database,Database 4 | shell,Shell 5 | concurrency,Concurrency 6 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | informational: true 6 | patch: 7 | default: 8 | informational: true 9 | codecov: 10 | token: 5092e877-785c-4f28-8ff7-c9c64fcacbb3 -------------------------------------------------------------------------------- /src/leetscrape/__init__.py: -------------------------------------------------------------------------------- 1 | from .extract_solution import ExtractSolutions 2 | from .generate_code_stub import GenerateCodeStub 3 | from .models import Question 4 | from .question import GetQuestion 5 | from .questions_list import GetQuestionsList 6 | 7 | __all__ = [ExtractSolutions, GenerateCodeStub, Question, GetQuestion, GetQuestionsList] 8 | __version__ = "1.0.2" 9 | -------------------------------------------------------------------------------- /tests/test_questions_list.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | from leetscrape import GetQuestionsList 5 | 6 | 7 | class TestGetQuestionsList: 8 | def test_scrape(self): 9 | ls = GetQuestionsList() 10 | ls.scrape() # Scrape the list of questions 11 | os.makedirs("./tests/data/") 12 | ls.to_csv(directory="./tests/data/") # Save 13 | shutil.rmtree("./tests/data/") # Remove 14 | -------------------------------------------------------------------------------- /example/solutions/test_q_0009_palindromeNumber.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from q_0009_palindromeNumber import Solution 3 | 4 | 5 | @pytest.mark.parametrize("x, output", [(121, True), (-121, False), (10, False)]) 6 | class TestSolution: 7 | def test_isPalindrome(self, x: int, output: bool): 8 | sc = Solution() 9 | assert ( 10 | sc.isPalindrome( 11 | x, 12 | ) 13 | == output 14 | ) 15 | -------------------------------------------------------------------------------- /example/solutions/test_q_0485_maxConsecutiveOnes.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from q_0485_maxConsecutiveOnes import Solution 3 | 4 | 5 | @pytest.mark.parametrize( 6 | "nums, output", [([1, 1, 0, 1, 1, 1], 3), ([1, 0, 1, 1, 0, 1], 2)] 7 | ) 8 | class TestSolution: 9 | def test_findMaxConsecutiveOnes(self, nums: List[int], output: int): 10 | sc = Solution() 11 | assert ( 12 | sc.findMaxConsecutiveOnes( 13 | nums, 14 | ) 15 | == output 16 | ) 17 | -------------------------------------------------------------------------------- /tests/test__helper.py: -------------------------------------------------------------------------------- 1 | from leetscrape._helper import camel_case, parse_args 2 | 3 | 4 | def test_camel_case(): 5 | assert camel_case("hello_world") == "helloWorld" 6 | assert camel_case("leet_code") == "leetCode" 7 | assert camel_case("python_programming") == "pythonProgramming" 8 | assert camel_case("a_b_c") == "aBC" 9 | assert camel_case("x_y_z") == "xYZ" 10 | 11 | 12 | def test_parse_args(): 13 | args = "x=10, y='hello', z=[1, 2, 3]" 14 | expected_result = {"x": 10, "y": "hello", "z": [1, 2, 3]} 15 | assert parse_args(args) == expected_result 16 | -------------------------------------------------------------------------------- /example/solutions/test_q_1946_largestNumberAfterMutatingSubstring.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from q_1946_largestNumberAfterMutatingSubstring import Solution 3 | 4 | 5 | @pytest.mark.parametrize( 6 | "num, change, output", 7 | [ 8 | ("132", [9, 8, 5, 0, 3, 6, 4, 2, 6, 8], "832"), 9 | ("021", [9, 4, 3, 5, 7, 2, 1, 9, 0, 6], "934"), 10 | ("5", [1, 4, 7, 5, 3, 2, 5, 6, 9, 4], "5"), 11 | ], 12 | ) 13 | class TestSolution: 14 | def test_maximumNumber(self, num: str, change: list[int], output: str): 15 | sc = Solution() 16 | assert ( 17 | sc.maximumNumber( 18 | num, 19 | change, 20 | ) 21 | == output 22 | ) 23 | -------------------------------------------------------------------------------- /docs/config/generate_code_stubs.md: -------------------------------------------------------------------------------- 1 | # GenerateCodeStubs 2 | 3 | Generate code stubs for a question 4 | 5 | ```python 6 | from leetscrape import GenerateCodeStub 7 | 8 | # Get the question body 9 | fcs = GenerateCodeStub(titleSlug="two-sum") 10 | fcs.generate(directory="") 11 | ``` 12 | This generates the following files in the given directory: 13 | - `q_0001_twoSum.py` - Python file with the code stub for the given question with a function named `twoSum`. 14 | - `test_q_0001_twoSum.py` - Python file with the test cases for the given question. 15 | 16 | See [examples](https://github.com/nikhil-ravi/LeetScrape/tree/main/example/solutions) for examples of the generated code stubs. 17 | 18 | ::: leetscrape.GenerateCodeStub 19 | options: 20 | show_source: true 21 | heading_level: 2 -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from leetscrape.utils import get_all_questions_body # combine_list_and_info, 4 | 5 | # def test_combine_list_and_info(): 6 | # with open("./example/data/questionBody.pickle", "rb") as f: 7 | # data = pickle.load(f) 8 | # questions_body = pd.DataFrame(data).drop(columns=["titleSlug"]) 9 | # questions_body["QID"] = questions_body["QID"].astype(int) 10 | # questions = pd.read_csv("./example/data/questions.csv") 11 | # questions = combine_list_and_info( 12 | # info_df=questions_body, list_df=questions, save_to="./all.json" 13 | # ) 14 | # os.remove("./all.json") 15 | 16 | 17 | def test_get_all_questions_body(): 18 | get_all_questions_body( 19 | ["two-sum", "add-two-numbers"], [False, False], "./dump.pickle" 20 | ) 21 | os.remove("./dump.pickle") 22 | -------------------------------------------------------------------------------- /docs/config/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.2] - 2024-04-16 4 | 5 | ### Changed 6 | - Added requests header to prevent 403 error when scraping questions. 7 | - Fixed a typo in the example notebook. 8 | 9 | 10 | ## [1.0.1] - 2024-01-04 11 | 12 | ### Changed 13 | - Updated the pyproject.toml file to make `marko` a required dependency. It was previously an extra `file` dependency. I had included it as an extra so that users who simply want to get question information would not have to install `marko` as well. However, seeing as `leetscrape question ` is a core feature of the package, I have decided to make `marko` a required dependency. 14 | 15 | ### Docs 16 | - Added this changelog section to the docs. 17 | - Fixed inactive badges in the Homepage. 18 | 19 | ### README 20 | - Updated the README to call out the new Changelog page on the docs. -------------------------------------------------------------------------------- /src/leetscrape/_helper.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import re 3 | 4 | 5 | def camel_case(s: str) -> str: 6 | """ 7 | Convert a string to camel case. 8 | 9 | Args: 10 | s (str): The input string. 11 | 12 | Returns: 13 | str: The camel case version of the input string. 14 | """ 15 | s = re.sub(r"(_|-)+", " ", s).title().replace(" ", "") 16 | return "".join([s[0].lower(), s[1:]]) 17 | 18 | 19 | def parse_args(args: str) -> dict: 20 | """A method to parse the arguments of a python method given in string format. 21 | 22 | Args: 23 | args (str): The arguments of a method in string format. 24 | 25 | Returns: 26 | dict: A dictionary of argument value pairs. 27 | """ 28 | args = "f({})".format(args) 29 | tree = ast.parse(args) 30 | funccall = tree.body[0].value # type: ignore 31 | args = {arg.arg: ast.literal_eval(arg.value) for arg in funccall.keywords} # type: ignore 32 | return args # type: ignore 33 | -------------------------------------------------------------------------------- /docs/config/question.md: -------------------------------------------------------------------------------- 1 | # GetQuestion 2 | 3 | Query individual question's information such as the body, test cases, constraints, hints, code stubs, and company tags using the `GetQuestion` class: 4 | 5 | ```python 6 | from leetscrape import GetQuestion 7 | 8 | # Get the question body 9 | question = GetQuestion(titleSlug="two-sum").scrape() 10 | ``` 11 | 12 | This returns a `Question` object with the following attributes: 13 | 14 | ```python 15 | question.QID # Question ID 16 | question.title # Question title 17 | question.titleSlug # Question title slug 18 | question.difficulty # Question difficulty 19 | question.Hints # Question hints 20 | question.Companies # Question companies 21 | question.topics # Question topic tags 22 | question.SimilarQuestions # Similar questions ids 23 | question.Code # Code stubs 24 | question.Body # Question body / problem statement 25 | question.isPaidOnly # Whether the question is only available to premium users of Leetcode 26 | ``` 27 | 28 | 29 | ::: leetscrape.GetQuestion 30 | options: 31 | show_source: true 32 | heading_level: 2 -------------------------------------------------------------------------------- /docs/config/leetscrape_ts.md: -------------------------------------------------------------------------------- 1 | # LeetScrape TS 2 | 3 | You can use the [leetscrape-ts](https://github.com/nikhil-ravi/leetscrape-ts) Next.js template to serve your solutions on the web. See the [demo](https://scuffedcode.nikhilravi.com/). Visit the repo for more details. You can generate the project using the `leetscrape ts` command: 4 | 5 | ```bash 6 | leetscrape ts --out ./ts 7 | ``` 8 | This will bootstrap the project in the given directory. Follow the instructions in the [README](https://github.com/nikhil-ravi/leetscrape-ts/blob/main/README.md) and create/modify the `.env.local` file. Then, run the following command to generate the mdx files: 9 | 10 | ```bash 11 | leetscrape solution --out ./ts/src/content/solutions ./solutions 12 | ``` 13 | 14 | You can then run the project using the following command: 15 | 16 | === "npm" 17 | ```bash 18 | cd ./ts 19 | npm run dev 20 | ``` 21 | === "yarn" 22 | ```bash 23 | cd ./ts 24 | yarn dev 25 | ``` 26 | === "pnpm" 27 | ```bash 28 | cd ./ts 29 | pnpm dev 30 | ``` 31 | === "bun" 32 | ```bash 33 | cd ./ts 34 | bun dev 35 | ``` -------------------------------------------------------------------------------- /docs/config/extract_solution.md: -------------------------------------------------------------------------------- 1 | # ExtractSolution 2 | 3 | Generate mdx files from solutions 4 | 5 | Once you have solved a question, you can generate an mdx file with the solution and the question statement using the `ExtractSolutions` class: 6 | 7 | ```python 8 | from leetscrape import ExtractSolutions 9 | 10 | # Get the question body 11 | solutions = ExtractSolutions(filename="").extract() 12 | ``` 13 | This outputs a list of `Solution` objects with the following attributes: 14 | 15 | ```python 16 | solution.id # Solution ID 17 | solution.code # Solution code 18 | solution.docs # Docstrings associated with the solution 19 | solution.problem_statement # Question body / problem statement 20 | ``` 21 | 22 | Alternatively, you can use the `to_mdx` method to generate the mdx file: 23 | 24 | ```python 25 | from leetscrape import ExtractSolutions 26 | 27 | # Get the question body 28 | ExtractSolutions(filename="").to_mdx(output_filename="") 29 | ``` 30 | 31 | ::: leetscrape.ExtractSolutions 32 | options: 33 | show_source: true 34 | heading_level: 2 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Nikhil Ravi 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 | -------------------------------------------------------------------------------- /tests/test_question.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pytest 4 | 5 | from leetscrape import GetQuestion, Question 6 | 7 | 8 | def get_test_cases(n: int = 8) -> list[str]: 9 | tc_data = json.load(open("./tests/test_cases.json")) 10 | tc_cases = [case["titleSlug"] for case in tc_data] 11 | return tc_cases[:n] 12 | 13 | 14 | # random_test_cases = ["edit-distance"] 15 | 16 | 17 | class TestQuestionInfo: 18 | def test_question_info(self): 19 | print( 20 | Question( 21 | QID=1, 22 | title="Two Sum", 23 | titleSlug="two-sum", 24 | difficulty="Easy", 25 | Hints=["1.", "2"], 26 | Companies=["amazon", "google"], 27 | SimilarQuestions=[2, 3], 28 | ) 29 | ) 30 | 31 | 32 | @pytest.mark.parametrize("titleSlug", sorted(get_test_cases())) 33 | class TestGetQuestionInfo: 34 | def test_scrape(self, titleSlug: str): 35 | print(titleSlug) 36 | gqi = GetQuestion(titleSlug) 37 | gqi.scrape() 38 | 39 | 40 | class TestGetQuestionInfoPaidOnly: 41 | def test_scrape(self): 42 | gqi = GetQuestion("max-consecutive-ones-ii") 43 | gqi.scrape() 44 | -------------------------------------------------------------------------------- /.github/workflows/pytest-and-docs.yml: -------------------------------------------------------------------------------- 1 | name: pytest-and-deploy-docs 2 | on: 3 | push: 4 | branches: 5 | - main 6 | permissions: 7 | contents: write 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-python@v4 14 | with: 15 | python-version: 3.x 16 | 17 | - name: Install poetry 18 | run: | 19 | python -m pip install poetry==1.3.2 20 | 21 | - name: Configure poetry 22 | run: | 23 | python -m poetry config virtualenvs.in-project true 24 | 25 | - name: Cache the virtualenv 26 | uses: actions/cache@v4 27 | with: 28 | path: ./.venv 29 | key: ${{ runner.os }}-venv-${{ hashFiles('**/poetry.lock') }} 30 | 31 | - name: Install dependencies 32 | run: | 33 | python -m poetry install --with testing,docs 34 | 35 | - name: Run tests 36 | run: | 37 | python -m poetry run python -m pytest tests -sxv --cov . 38 | - name: Upload coverage reports to Codecov 39 | uses: codecov/codecov-action@v3 40 | - name: Build docs 41 | run: | 42 | python -m poetry run mkdocs gh-deploy --force 43 | -------------------------------------------------------------------------------- /docs/config/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to LeetScrape 2 | 3 | [![deploy-docs](https://github.com/nikhil-ravi/LeetScrape/actions/workflows/pytest-and-docs.yml/badge.svg)](https://leetscrape.nikhilravi.com) [![PYPI](https://img.shields.io/pypi/v/leetscrape)](https://pypi.org/project/leetscrape/) [![codecov](https://codecov.io/gh/nikhil-ravi/LeetScrape/branch/main/graph/badge.svg?token=GWOVLPYSUA)](https://codecov.io/gh/nikhil-ravi/LeetScrape)![PyPI - Downloads](https://img.shields.io/pypi/dm/leetscrape) 4 | 5 | Introducing the LeetScrape - a powerful and efficient Python package designed to scrape problem statements and basic test cases from LeetCode.com. With this package, you can easily download and save LeetCode problems to your local machine, making it convenient for offline practice and studying. It is perfect for software engineers and students preparing for coding interviews. The package is lightweight, easy to use and can be integrated with other tools and IDEs. With the LeetScrape, you can boost your coding skills and improve your chances of landing your dream job. 6 | 7 | Use this package to get the list of Leetcode questions, their topic and company tags, difficulty, question body (including test cases, constraints, hints), and code stubs in any of the available programming languages. 8 | 9 | There is also a related Next.js web app to serve the scraped questions and your answers at [leetcode-nextjs](https://github.com/nikhil-ravi/leetcode-ts). See the [demo](https://scuffedcode.nikhilravi.com/). 10 | -------------------------------------------------------------------------------- /example/mdx/q_0485_maxConsecutiveOnes.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | qid: 485 3 | title: Max Consecutive Ones 4 | titleSlug: max-consecutive-ones 5 | difficulty: Easy 6 | tags: Array 7 | --- 8 | 9 | Given a binary array `nums`, return *the maximum number of consecutive* `1`*'s in the array*. 10 | 11 | 12 | 13 | **Example 1:** 14 | 15 | ``` 16 | Input: nums = [1,1,0,1,1,1] 17 | Output: 3 18 | Explanation: The first two digits or the last three digits are consecutive 1s. The maximum number of consecutive 1s is 3. 19 | ``` 20 | **Example 2:** 21 | 22 | ``` 23 | Input: nums = [1,0,1,1,0,1] 24 | Output: 2 25 | ``` 26 | 27 | 28 | **Constraints:** 29 | 30 | * `1 <= nums.length <= 10^{5}` 31 | * `nums[i]` is either `0` or `1`. 32 | 33 | ## Solutions 34 | 35 | ```python 36 | class Solution: 37 | def findMaxConsecutiveOnes(self, nums: list[int]) -> int: 38 | new_sum = 0 39 | max_num = 0 40 | for num in nums: 41 | if num == 1: 42 | new_sum += 1 43 | if new_sum > max_num: 44 | max_num = new_sum 45 | continue 46 | new_sum = 0 47 | return max_num 48 | ``` 49 | 50 | Find the maximum number of consecutive ones in a given binary array. 51 | 52 | Keeps a count starting at the first encountered `1` and resets the count once a zero is encounterd. Returns the maximum of such counts. 53 | 54 | **Time Complexity**: `O(n)`, We iterate through the array. 55 | **Space Complexity**: `O(1)`, We do not use any more space. 56 | 57 | -------------------------------------------------------------------------------- /src/leetscrape/models.py: -------------------------------------------------------------------------------- 1 | from typing import Literal 2 | 3 | from markdownify import markdownify as md 4 | from pydantic import Field 5 | from pydantic.dataclasses import dataclass 6 | 7 | Difficulty = Literal["Easy", "Medium", "Hard"] 8 | 9 | 10 | @dataclass 11 | class Question: 12 | QID: int 13 | title: str 14 | titleSlug: str 15 | difficulty: Difficulty = Field(default_factory=Difficulty) 16 | Hints: list[str] = Field(default_factory=list) 17 | Companies: list[str] | None = None 18 | topics: list[str] | None = Field(default_factory=list) 19 | SimilarQuestions: list[int] = Field(default_factory=list) 20 | Code: str = Field(default_factory=str) 21 | Body: str = Field(default_factory=str) 22 | isPaidOnly: bool = False 23 | 24 | def __repr__(self) -> str: 25 | repr = f"{self.QID}. {self.titleSlug}\n" 26 | repr += md(self.Body) 27 | if len(self.Hints) > 1: 28 | repr += "Hints:\n" 29 | for idx, hint in enumerate(self.Hints): 30 | repr += f" {idx}. {hint}\n" 31 | if self.Companies is not None: 32 | repr += f"Companies: {self.Companies}\n" 33 | if len(self.SimilarQuestions) > 0: 34 | repr += f"SimilarQuestions: {self.SimilarQuestions}\n" 35 | return repr 36 | 37 | 38 | @dataclass 39 | class Solution: 40 | id: int 41 | code: str 42 | docs: dict | None = None 43 | problem_statement: str | None = None 44 | 45 | def __repr__(self) -> str: 46 | repr = f"{self.id}.\n{self.code}\n" 47 | return repr 48 | -------------------------------------------------------------------------------- /tests/test_generate_code_stub.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | import pytest 5 | 6 | from leetscrape import GenerateCodeStub 7 | 8 | 9 | def get_test_cases(n: int = 8) -> list[str]: 10 | tc_data = json.load(open("./tests/test_cases.json")) 11 | tc_cases = [case["titleSlug"] for case in tc_data] 12 | return tc_cases[:n] 13 | 14 | 15 | @pytest.mark.parametrize("titleSlug", sorted(get_test_cases())) 16 | class TestGenerateCodeStub: 17 | def test_generate(self, titleSlug: str): 18 | print(titleSlug) 19 | gqi = GenerateCodeStub(titleSlug=titleSlug) 20 | gqi.generate(testing=True) 21 | 22 | 23 | class TestGenerateCodeStubIllegalTitleSlug: 24 | def test_generate_valid_titleSlug(self): 25 | gqi = GenerateCodeStub(titleSlug="two-sum") 26 | gqi.generate() 27 | os.remove("./q_0001_twoSum.py") 28 | os.remove("./test_q_0001_twoSum.py") 29 | 30 | def test_generate_valid_qid(self): 31 | GenerateCodeStub(qid=1) 32 | 33 | def test_generate_illegal_titleSlug(self): 34 | with pytest.raises(ValueError): 35 | GenerateCodeStub(titleSlug="no-question-like-this") 36 | 37 | def test_generate_illegal_qid(self): 38 | with pytest.raises(ValueError): 39 | GenerateCodeStub(qid=-1) 40 | 41 | def test_generate_qid_titleSlug_mismatch(self): 42 | with pytest.raises(ValueError): 43 | GenerateCodeStub(qid=1, titleSlug="string-to-integer-atoi") 44 | 45 | def test_generate_neither_qid_titleSlug_passed(self): 46 | with pytest.raises(ValueError): 47 | GenerateCodeStub() 48 | -------------------------------------------------------------------------------- /docs/config/installation.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Installation 4 | 5 | Start by installing the package from pip or conda: 6 | === "pip" 7 | ```bash 8 | pip install leetscrape 9 | ``` 10 | === "conda" 11 | ```bash 12 | conda install leetscrape 13 | ``` 14 | === "poetry" 15 | ```bash 16 | poetry add leetscrape 17 | ``` 18 | 19 | ## Commands 20 | 21 | * leetscrape list [--out OUT] - List all questions without generating code stub. 22 | 23 | ``` 24 | options: 25 | -h, --help show a help message and exit 26 | --out OUT, -o OUT Specify the output file name to store the list of questions. 27 | ``` 28 | 29 | * leetscrape question [--out OUT] qid [qid ...] - Generate a code stub for the given question(s). 30 | 31 | ``` 32 | positional arguments: 33 | qid Enter Leetcode question ID(s) 34 | 35 | options: 36 | -h, --help show this help message and exit 37 | --out OUT, -o OUT Enter the path to the output directory 38 | ``` 39 | 40 | * leetscrape solution [-h] [--out OUT] input - Generate mdx files from solutions. 41 | 42 | ``` 43 | positional arguments: 44 | input Enter the path to the solution directory with solution files or to a single 45 | solution file 46 | 47 | options: 48 | -h, --help show this help message and exit 49 | --out OUT, -o OUT Enter the path to the output directory to save solutions mdx files 50 | ``` 51 | 52 | * leetscrape ts [--out OUT] - Create the leetscrape-ts Next.js project to host the solutions. 53 | 54 | ``` 55 | options: 56 | -h, --help show this help message and exit 57 | --out OUT, -o OUT Enter the path to the output directory to save the project 58 | ``` -------------------------------------------------------------------------------- /example/solutions/q_0485_maxConsecutiveOnes.py: -------------------------------------------------------------------------------- 1 | front_matter = { 2 | "qid": 485, 3 | "title": "Max Consecutive Ones", 4 | "titleSlug": "max-consecutive-ones", 5 | "difficulty": "Easy", 6 | "tags": ["Array"], 7 | } 8 | 9 | 10 | # ====================== DO NOT EDIT ABOVE THIS LINE ====================== 11 | class Solution: 12 | """Given a binary array `nums`, return *the maximum number of consecutive* `1`*'s in the array*. 13 | 14 | 15 | 16 | **Example 1:** 17 | 18 | ``` 19 | Input: nums = [1,1,0,1,1,1] 20 | Output: 3 21 | Explanation: The first two digits or the last three digits are consecutive 1s. The maximum number of consecutive 1s is 3. 22 | ``` 23 | **Example 2:** 24 | 25 | ``` 26 | Input: nums = [1,0,1,1,0,1] 27 | Output: 2 28 | ``` 29 | 30 | 31 | **Constraints:** 32 | 33 | * `1 <= nums.length <= 10^{5}` 34 | * `nums[i]` is either `0` or `1`. 35 | """ 36 | 37 | def findMaxConsecutiveOnes(self, nums: list[int]) -> int: 38 | """Find the maximum number of consecutive ones in a given binary array. 39 | 40 | Keeps a count starting at the first encountered `1` and resets the count once a zero is encounterd. Returns the maximum of such counts. 41 | 42 | Args: 43 | nums (list[int]): The binary array. 44 | 45 | Returns: 46 | int: The maximum number of consecutive ones in the array. 47 | 48 | Time Complexity: 49 | `O(n)`: We iterate through the array. 50 | 51 | Space Complexity: 52 | `O(1)`: We do not use any more space. 53 | """ 54 | new_sum = 0 55 | max_num = 0 56 | for num in nums: 57 | if num == 1: 58 | new_sum += 1 59 | if new_sum > max_num: 60 | max_num = new_sum 61 | continue 62 | new_sum = 0 63 | return max_num 64 | 65 | # If you have multiple solutions, add them all here as methods of the same class. 66 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "leetscrape" 3 | version = "1.0.2" 4 | description = "Introducing LeetScrape - a powerful and efficient Python package designed to scrape problem statements and their topic and company tags, difficulty, test cases, hints, and code stubs from LeetCode.com. Easily download and save LeetCode problems to your local machine, making it convenient for offline practice and studying. It is perfect for anyone preparing for coding interviews. With the LeetScrape, you can boost your coding skills and improve your chances of landing your dream job." 5 | authors = ["Nikhil Ravi "] 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/nikhil-ravi/LeetScrape" 9 | documentation = "https://leetscrape.nikhilravi.com/" 10 | 11 | [tool.poetry.dependencies] 12 | python = "^3.10" 13 | black = "^22.12.0" 14 | docstring-parser = "^0.15" 15 | markdownify = "^0.11.6" 16 | marko = "^1.2.2" 17 | numpy = "<2.0" 18 | pandas = "^1.5.2" 19 | pydantic = "^1.10.4" 20 | requests = "^2.28.2" 21 | tqdm = "^4.64.1" 22 | 23 | [tool.poetry.group.dev] 24 | optional = true 25 | [tool.poetry.group.dev.dependencies] 26 | ipykernel = "^6.20.2" 27 | flake8 = "^6.0.0" 28 | isort = "^5.13.2" 29 | 30 | [tool.poetry.group.testing] 31 | optional = true 32 | [tool.poetry.group.testing.dependencies] 33 | pytest = "^7.2.1" 34 | pytest-xdist = "^3.1.0" 35 | pytest-html = "^3.2.0" 36 | coverage = "^7.0.5" 37 | pytest-cov = "^4.0.0" 38 | 39 | 40 | [tool.poetry.group.docs] 41 | optional = true 42 | [tool.poetry.group.docs.dependencies] 43 | mkdocs = "^1.4.2" 44 | mkdocs-material = "^9.5.3" 45 | mkdocstrings = { extras = ["python"], version = "^0.24.0" } 46 | mkdocs-git-revision-date-localized-plugin = "^1.1.0" 47 | griffe = "^0.38.1" 48 | 49 | [build-system] 50 | requires = ["poetry-core"] 51 | build-backend = "poetry.core.masonry.api" 52 | 53 | [tool.pytest.ini_options] 54 | pythonpath = "src" 55 | testpaths = ["tests"] 56 | minversion = "6.0" 57 | addopts = "-ra -q" 58 | 59 | [tool.poetry.scripts] 60 | leetscrape = "leetscrape.scripts:leetscrape" 61 | leetupload_solution = "leetscrape.scripts:leetupload_solution" 62 | -------------------------------------------------------------------------------- /example/data/topicTags.csv: -------------------------------------------------------------------------------- 1 | slug,name 2 | array,Array 3 | string,String 4 | hash-table,Hash Table 5 | dynamic-programming,Dynamic Programming 6 | math,Math 7 | sorting,Sorting 8 | greedy,Greedy 9 | depth-first-search,Depth-First Search 10 | database,Database 11 | breadth-first-search,Breadth-First Search 12 | binary-search,Binary Search 13 | tree,Tree 14 | matrix,Matrix 15 | binary-tree,Binary Tree 16 | two-pointers,Two Pointers 17 | bit-manipulation,Bit Manipulation 18 | stack,Stack 19 | heap-priority-queue,Heap (Priority Queue) 20 | design,Design 21 | graph,Graph 22 | prefix-sum,Prefix Sum 23 | simulation,Simulation 24 | counting,Counting 25 | backtracking,Backtracking 26 | sliding-window,Sliding Window 27 | union-find,Union Find 28 | linked-list,Linked List 29 | ordered-set,Ordered Set 30 | monotonic-stack,Monotonic Stack 31 | enumeration,Enumeration 32 | recursion,Recursion 33 | trie,Trie 34 | divide-and-conquer,Divide and Conquer 35 | binary-search-tree,Binary Search Tree 36 | bitmask,Bitmask 37 | queue,Queue 38 | memoization,Memoization 39 | geometry,Geometry 40 | segment-tree,Segment Tree 41 | topological-sort,Topological Sort 42 | number-theory,Number Theory 43 | hash-function,Hash Function 44 | binary-indexed-tree,Binary Indexed Tree 45 | game-theory,Game Theory 46 | data-stream,Data Stream 47 | interactive,Interactive 48 | string-matching,String Matching 49 | rolling-hash,Rolling Hash 50 | shortest-path,Shortest Path 51 | combinatorics,Combinatorics 52 | randomized,Randomized 53 | brainteaser,Brainteaser 54 | monotonic-queue,Monotonic Queue 55 | merge-sort,Merge Sort 56 | iterator,Iterator 57 | concurrency,Concurrency 58 | doubly-linked-list,Doubly-Linked List 59 | probability-and-statistics,Probability and Statistics 60 | quickselect,Quickselect 61 | bucket-sort,Bucket Sort 62 | suffix-array,Suffix Array 63 | minimum-spanning-tree,Minimum Spanning Tree 64 | counting-sort,Counting Sort 65 | shell,Shell 66 | line-sweep,Line Sweep 67 | reservoir-sampling,Reservoir Sampling 68 | eulerian-circuit,Eulerian Circuit 69 | radix-sort,Radix Sort 70 | strongly-connected-component,Strongly Connected Component 71 | rejection-sampling,Rejection Sampling 72 | biconnected-component,Biconnected Component 73 | -------------------------------------------------------------------------------- /example/mdx/q_0009_palindromeNumber.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | qid: 9 3 | title: Palindrome Number 4 | titleSlug: palindrome-number 5 | difficulty: Easy 6 | tags: Math 7 | --- 8 | 9 | Given an integer `x`, return `true` *if* `x` *is a* ***palindrome****, and* `false` *otherwise*. 10 | 11 | 12 | 13 | **Example 1:** 14 | 15 | ``` 16 | Input: x = 121 17 | Output: true 18 | Explanation: 121 reads as 121 from left to right and from right to left. 19 | ``` 20 | **Example 2:** 21 | 22 | ``` 23 | Input: x = -121 24 | Output: false 25 | Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. 26 | ``` 27 | **Example 3:** 28 | 29 | ``` 30 | Input: x = 10 31 | Output: false 32 | Explanation: Reads 01 from right to left. Therefore it is not a palindrome. 33 | ``` 34 | 35 | 36 | **Constraints:** 37 | 38 | * `-2^{31} <= x <= 2^{31} - 1` 39 | 40 | 41 | 42 | **Follow up:** Could you solve it without converting the integer to a string? 43 | 44 | ## Solutions 45 | 46 | ### Method 1 47 | 48 | ```python 49 | class Solution: 50 | def isPalindrome(self, x: int) -> bool: 51 | if x < 0 or (x % 10 == 0 and x != 0): 52 | return False 53 | 54 | reversed = 0 55 | while x > reversed: 56 | reversed = reversed * 10 + x % 10 57 | x //= 10 58 | return (x == reversed) | (x == reversed // 10) 59 | ``` 60 | 61 | The question asks us to solve this without converting to a string. One way to do it then is to reverse the integer similar to Problem 7 and compare the two results. However, while reversing the integer, we might run into overflow errors. 62 | 63 | Thus, in this method, we only reverse half the digits (say, the latter half) and check if the first half is equal to the reversed second half. To figure out where in the number is the middle digit, we note that we have reversed enough digits when the reversed number is larger than the first half. 64 | 65 | **Time Complexity**: `O(log10(x))`, In each iteration of our while loop, we are dividing x by 10. 66 | **Space Complexity**: `O(1)`, We are not using any extra space other than to create the result. 67 | 68 | ### Method 2 69 | 70 | ```python 71 | class Solution: 72 | def isPalindrome_with_str_conversion(self, x: int) -> bool: 73 | return str(x) == str(x)[::-1] 74 | ``` 75 | 76 | Checks if a given integer is a palindrome. 77 | 78 | In this method, we first convert the given integer to a string and then check if it is equal to its reverse. 79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/config/questions_list.md: -------------------------------------------------------------------------------- 1 | # GetQuestionsList 2 | 3 | Get the list of problems and their information 4 | 5 | ```python 6 | from leetscrape import GetQuestionsList 7 | 8 | ls = GetQuestionsList() 9 | ls.scrape() # Scrape the list of questions 10 | ls.questions.head() # Get the list of questions 11 | ``` 12 | 13 | | | QID | title | titleSlug | difficulty | acceptanceRate | paidOnly | topicTags | categorySlug | 14 | |---:|------:|:-----------------------------------------------|:-----------------------------------------------|:-------------|-----------------:|:-----------|:---------------------------------------|:---------------| 15 | | 0 | 1 | Two Sum | two-sum | Easy | 51.4225 | False | array,hash-table | algorithms | 16 | | 1 | 2 | Add Two Numbers | add-two-numbers | Medium | 41.9051 | False | linked-list,math,recursion | algorithms | 17 | | 2 | 3 | Longest Substring Without Repeating Characters | longest-substring-without-repeating-characters | Medium | 34.3169 | False | hash-table,string,sliding-window | algorithms | 18 | | 3 | 4 | Median of Two Sorted Arrays | median-of-two-sorted-arrays | Hard | 38.8566 | False | array,binary-search,divide-and-conquer | algorithms | 19 | | 4 | 5 | Longest Palindromic Substring | longest-palindromic-substring | Medium | 33.4383 | False | string,dynamic-programming | algorithms | 20 | 21 | You can export the associated tables to a directory using the `to_csv` method: 22 | 23 | ```python 24 | ls.to_csv(directory="") 25 | ``` 26 | This generates 6 `.csv` files in the current directory: 27 | - `questions.csv` - List of questions with their title, difficulty, acceptance rate, paid status, topic tags, and category. 28 | - `companies.csv` - List of companies with their name, slug, and the questions count. 29 | - `topicsTags.csv` - List of topic tags with their name and slug. 30 | - `categories.csv` - List of categories with their name and slug. 31 | - `questionCategory.csv` - An edgelist of questions and their categories. 32 | - `questionTopics.csv` - An edgelist of questions and their topic tags. 33 | 34 | ::: leetscrape.GetQuestionsList 35 | options: 36 | show_source: true 37 | heading_level: 2 -------------------------------------------------------------------------------- /tests/q_0009_palindromeNumber_wo_frontmatter.py: -------------------------------------------------------------------------------- 1 | front_matter = [1, 2, 3] 2 | 3 | 4 | # ====================== DO NOT EDIT ABOVE THIS LINE ====================== 5 | class Solution: 6 | """Given an integer `x`, return `true` *if* `x` *is a* ***palindrome****, and* `false` *otherwise*. 7 | 8 | 9 | 10 | **Example 1:** 11 | 12 | ``` 13 | Input: x = 121 14 | Output: true 15 | Explanation: 121 reads as 121 from left to right and from right to left. 16 | ``` 17 | **Example 2:** 18 | 19 | ``` 20 | Input: x = -121 21 | Output: false 22 | Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. 23 | ``` 24 | **Example 3:** 25 | 26 | ``` 27 | Input: x = 10 28 | Output: false 29 | Explanation: Reads 01 from right to left. Therefore it is not a palindrome. 30 | ``` 31 | 32 | 33 | **Constraints:** 34 | 35 | * `-2^{31} <= x <= 2^{31} - 1` 36 | 37 | 38 | 39 | **Follow up:** Could you solve it without converting the integer to a string?""" 40 | 41 | def isPalindrome(self, x: int) -> bool: 42 | """ 43 | The question asks us to solve this without converting to a string. One way to do it then is to reverse the integer similar to Problem 7 and compare the two results. However, while reversing the integer, we might run into overflow errors. 44 | 45 | Thus, in this method, we only reverse half the digits (say, the latter half) and check if the first half is equal to the reversed second half. To figure out where in the number is the middle digit, we note that we have reversed enough digits when the reversed number is larger than the first half. 46 | 47 | Args: 48 | x (int): The number that is to be tested for a palindrome. 49 | 50 | Returns: 51 | bool: True if the number is a palindrome, False otherwise. Negative numbers are not considered as palindromes. 52 | 53 | Time Complexity: 54 | `O(log10(x))`: In each iteration of our while loop, we are dividing x by 10. 55 | 56 | Space Complexity: 57 | `O(1)`: We are not using any extra space other than to create the result. 58 | """ 59 | if x < 0 or (x % 10 == 0 and x != 0): 60 | return False 61 | 62 | reversed = 0 63 | while x > reversed: 64 | reversed = reversed * 10 + x % 10 65 | x //= 10 66 | return (x == reversed) | (x == reversed // 10) 67 | 68 | # If you have multiple solutions, add them all here as methods of the same class. 69 | def isPalindrome_with_str_conversion(self, x: int) -> bool: 70 | return str(x) == str(x)[::-1] 71 | -------------------------------------------------------------------------------- /tests/q_0009_palindromeNumber.py: -------------------------------------------------------------------------------- 1 | front_matter = { 2 | "qid": 9, 3 | "title": "Palindrome Number", 4 | "titleSlug": "palindrome-number", 5 | "difficulty": "Easy", 6 | "tags": ["Math"], 7 | } 8 | 9 | 10 | # ====================== DO NOT EDIT ABOVE THIS LINE ====================== 11 | class Solution: 12 | """Given an integer `x`, return `true` *if* `x` *is a* ***palindrome****, and* `false` *otherwise*. 13 | 14 | 15 | 16 | **Example 1:** 17 | 18 | ``` 19 | Input: x = 121 20 | Output: true 21 | Explanation: 121 reads as 121 from left to right and from right to left. 22 | ``` 23 | **Example 2:** 24 | 25 | ``` 26 | Input: x = -121 27 | Output: false 28 | Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. 29 | ``` 30 | **Example 3:** 31 | 32 | ``` 33 | Input: x = 10 34 | Output: false 35 | Explanation: Reads 01 from right to left. Therefore it is not a palindrome. 36 | ``` 37 | 38 | 39 | **Constraints:** 40 | 41 | * `-2^{31} <= x <= 2^{31} - 1` 42 | 43 | 44 | 45 | **Follow up:** Could you solve it without converting the integer to a string?""" 46 | 47 | def isPalindrome(self, x: int) -> bool: 48 | """ 49 | The question asks us to solve this without converting to a string. One way to do it then is to reverse the integer similar to Problem 7 and compare the two results. However, while reversing the integer, we might run into overflow errors. 50 | 51 | Thus, in this method, we only reverse half the digits (say, the latter half) and check if the first half is equal to the reversed second half. To figure out where in the number is the middle digit, we note that we have reversed enough digits when the reversed number is larger than the first half. 52 | 53 | Args: 54 | x (int): The number that is to be tested for a palindrome. 55 | 56 | Returns: 57 | bool: True if the number is a palindrome, False otherwise. Negative numbers are not considered as palindromes. 58 | 59 | Time Complexity: 60 | `O(log10(x))`: In each iteration of our while loop, we are dividing x by 10. 61 | 62 | Space Complexity: 63 | `O(1)`: We are not using any extra space other than to create the result. 64 | """ 65 | if x < 0 or (x % 10 == 0 and x != 0): 66 | return False 67 | 68 | reversed = 0 69 | while x > reversed: 70 | reversed = reversed * 10 + x % 10 71 | x //= 10 72 | return (x == reversed) | (x == reversed // 10) 73 | 74 | # If you have multiple solutions, add them all here as methods of the same class. 75 | def isPalindrome_with_str_conversion(self, x: int) -> bool: 76 | return str(x) == str(x)[::-1] 77 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: LeetScrape 2 | site_url: https://leetscrape.nikhilravi.com/ 3 | docs_dir: "docs/config" 4 | site_dir: "docs/build" 5 | 6 | plugins: 7 | - privacy 8 | - search 9 | - mkdocstrings: 10 | handlers: 11 | python: 12 | paths: [src] 13 | - git-revision-date-localized: 14 | enable_creation_date: true 15 | 16 | theme: 17 | name: material 18 | highlightjs: true 19 | features: 20 | - navigation.instant 21 | - navigation.instant.prefetching 22 | - navigation.instant.progress 23 | - navigation.tracking 24 | - navigation.sections 25 | - navigation.top 26 | - navigation.footer 27 | - search.suggest 28 | - search.highlight 29 | - heading.autohide 30 | - content.action.edit 31 | - content.action.view 32 | - content.code.copy 33 | - content.code.select 34 | 35 | palette: 36 | # Palette toggle for automatic mode 37 | - media: "(prefers-color-scheme)" 38 | toggle: 39 | icon: material/brightness-auto 40 | name: Switch to light mode 41 | 42 | # Palette toggle for light mode 43 | - media: "(prefers-color-scheme: light)" 44 | scheme: default 45 | toggle: 46 | icon: material/brightness-7 47 | name: Switch to dark mode 48 | 49 | # Palette toggle for dark mode 50 | - media: "(prefers-color-scheme: dark)" 51 | scheme: slate 52 | primary: red 53 | accent: deep_orange 54 | toggle: 55 | icon: material/brightness-4 56 | name: Switch to light mode 57 | 58 | watch: 59 | - src 60 | 61 | markdown_extensions: 62 | - smarty 63 | - toc: 64 | permalink: True 65 | - sane_lists 66 | - pymdownx.superfences 67 | - pymdownx.tabbed: 68 | alternate_style: true 69 | - pymdownx.highlight: 70 | anchor_linenums: true 71 | line_spans: __span 72 | pygments_lang_class: true 73 | - pymdownx.inlinehilite 74 | - pymdownx.snippets 75 | 76 | nav: 77 | - index.md 78 | - installation.md 79 | - API: 80 | - questions_list.md 81 | - question.md 82 | - generate_code_stubs.md 83 | - extract_solution.md 84 | - leetscrape_ts.md 85 | - CHANGELOG.md 86 | 87 | extra: 88 | analytics: 89 | provider: google 90 | property: G-LL26YLB3M5 91 | social: 92 | - icon: fontawesome/brands/github 93 | link: https://www.github.com/nikhil-ravi 94 | - icon: fontawesome/brands/linkedin 95 | link: https://www.linkedin.com/in/nikhil--ravi 96 | - icon: fontawesome/brands/google-scholar 97 | link: https://scholar.google.com/citations?user=Z4Z3QYIAAAAJ&hl=en 98 | 99 | repo_url: https://github.com/nikhil-ravi/LeetScrape 100 | repo_name: nikhil-ravi/LeetScrape 101 | edit_uri: tree/main/docs/config 102 | -------------------------------------------------------------------------------- /src/leetscrape/utils.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from tqdm import tqdm 6 | 7 | from .question import GetQuestion 8 | 9 | """A set of helper functions to transform and query the scraped data.""" 10 | 11 | 12 | def combine_list_and_info( 13 | list_df: pd.DataFrame, info_df: pd.DataFrame, save_to: str = "" 14 | ) -> pd.DataFrame: 15 | """ 16 | Combines the questions list dataframe with the questions info dataframe by QID 17 | and return the combined dataframe where each record contains the QID, title, 18 | titleSlug, hints, difficulty, acceptance rate, similar questions, topic tags, 19 | category, code stubs, body, and companies. 20 | 21 | Args: 22 | list_df (pd.DataFrame): Dataframe that contains the list of questions. 23 | info_df (pd.DataFrame): Dataframe that contains the additional information of questions. 24 | save_to (str): If provided, saves the resulting dataframe to a json file with the given name. Defaults to "". 25 | 26 | Returns: 27 | pd.DataFrame: The combined dataframe. 28 | """ 29 | questions = pd.concat( 30 | [list_df.set_index("QID"), info_df.set_index("QID")], axis=1 31 | ).reset_index() 32 | questions["Hints"] = questions["Hints"].fillna("").apply(list) 33 | questions["SimilarQuestions"] = questions["SimilarQuestions"].fillna("").apply(list) 34 | questions["SimilarQuestions"] = questions["SimilarQuestions"].apply( 35 | lambda w: [int(q) for q in w] 36 | ) 37 | questions["Code"] = questions["Code"].fillna("") 38 | questions["Body"] = questions["Body"].fillna("") 39 | questions["Companies"] = ( 40 | questions["Companies"].fillna(np.nan).replace([np.nan], [None]) 41 | ) 42 | if len(save_to) > 0: 43 | questions.to_json(save_to, orient="records") 44 | return questions 45 | 46 | 47 | def get_all_questions_body( 48 | titleSlugs, isPaidOnlyList, save_to: str = "../example/data/dump.pickle" 49 | ) -> list[dict[str, str | int]]: 50 | """ 51 | Get the body of all questions in the list and save it to a file. 52 | 53 | Args: 54 | titleSlugs (List[str]): A list of titleSlugs of questions. 55 | isPaidOnlyList (List[bool]): A list of isPaidOnly property of questions, indicating whether the question is subscriber only. 56 | save_to (str): The path to save the scraped data. 57 | 58 | Returns: 59 | list[dict[str, str|int]]: A list of dictionaries containing the question information 60 | """ 61 | questions_info_list = [] 62 | for i, (titleSlug, paidOnly) in enumerate(tqdm(zip(titleSlugs, isPaidOnlyList))): 63 | if not paidOnly: 64 | questions_info_list.append(GetQuestion(titleSlug).scrape()) 65 | if i % 10 == 0: 66 | with open(save_to, "wb") as f: 67 | pickle.dump(questions_info_list, f) 68 | 69 | with open(save_to, "wb") as f: 70 | pickle.dump(questions_info_list, f) 71 | return questions_info_list 72 | -------------------------------------------------------------------------------- /example/solutions/q_0009_palindromeNumber.py: -------------------------------------------------------------------------------- 1 | front_matter = { 2 | "qid": 9, 3 | "title": "Palindrome Number", 4 | "titleSlug": "palindrome-number", 5 | "difficulty": "Easy", 6 | "tags": ["Math"], 7 | } 8 | 9 | 10 | # ====================== DO NOT EDIT ABOVE THIS LINE ====================== 11 | class Solution: 12 | """Given an integer `x`, return `true` *if* `x` *is a* ***palindrome****, and* `false` *otherwise*. 13 | 14 | 15 | 16 | **Example 1:** 17 | 18 | ``` 19 | Input: x = 121 20 | Output: true 21 | Explanation: 121 reads as 121 from left to right and from right to left. 22 | ``` 23 | **Example 2:** 24 | 25 | ``` 26 | Input: x = -121 27 | Output: false 28 | Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. 29 | ``` 30 | **Example 3:** 31 | 32 | ``` 33 | Input: x = 10 34 | Output: false 35 | Explanation: Reads 01 from right to left. Therefore it is not a palindrome. 36 | ``` 37 | 38 | 39 | **Constraints:** 40 | 41 | * `-2^{31} <= x <= 2^{31} - 1` 42 | 43 | 44 | 45 | **Follow up:** Could you solve it without converting the integer to a string?""" 46 | 47 | def isPalindrome(self, x: int) -> bool: 48 | """ 49 | The question asks us to solve this without converting to a string. One way to do it then is to reverse the integer similar to Problem 7 and compare the two results. However, while reversing the integer, we might run into overflow errors. 50 | 51 | Thus, in this method, we only reverse half the digits (say, the latter half) and check if the first half is equal to the reversed second half. To figure out where in the number is the middle digit, we note that we have reversed enough digits when the reversed number is larger than the first half. 52 | 53 | Args: 54 | x (int): The number that is to be tested for a palindrome. 55 | 56 | Returns: 57 | bool: True if the number is a palindrome, False otherwise. Negative numbers are not considered as palindromes. 58 | 59 | Time Complexity: 60 | `O(log10(x))`: In each iteration of our while loop, we are dividing x by 10. 61 | 62 | Space Complexity: 63 | `O(1)`: We are not using any extra space other than to create the result. 64 | """ 65 | if x < 0 or (x % 10 == 0 and x != 0): 66 | return False 67 | 68 | reversed = 0 69 | while x > reversed: 70 | reversed = reversed * 10 + x % 10 71 | x //= 10 72 | return (x == reversed) | (x == reversed // 10) 73 | 74 | # If you have multiple solutions, add them all here as methods of the same class. 75 | def isPalindrome_with_str_conversion(self, x: int) -> bool: 76 | """Checks if a given integer is a palindrome. 77 | 78 | In this method, we first convert the given integer to a string and then check if it is equal to its reverse. 79 | 80 | Args: 81 | x (int): The number that is to be tested for a palindrome. 82 | 83 | Returns: 84 | bool: True if the number is a palindrome, False otherwise. Negative numbers are not considered as palindromes. 85 | """ 86 | return str(x) == str(x)[::-1] 87 | -------------------------------------------------------------------------------- /example/mdx/q_1946_largestNumberAfterMutatingSubstring.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | qid: 1946 3 | title: Largest Number After Mutating Substring 4 | titleSlug: largest-number-after-mutating-substring 5 | difficulty: Medium 6 | tags: Array, String, Greedy 7 | --- 8 | 9 | You are given a string `num`, which represents a large integer. You are also given a **0-indexed** integer array `change` of length `10` that maps each digit `0-9` to another digit. More formally, digit `d` maps to digit `change[d]`. 10 | 11 | You may **choose** to **mutate a single substring** of `num`. To mutate a substring, replace each digit `num[i]` with the digit it maps to in `change` (i.e. replace `num[i]` with `change[num[i]]`). 12 | 13 | Return *a string representing the **largest** possible integer after **mutating** (or choosing not to) a **single substring** of* `num`. 14 | 15 | A **substring** is a contiguous sequence of characters within the string. 16 | 17 | 18 | 19 | **Example 1:** 20 | 21 | ``` 22 | Input: num = "132", change = [9,8,5,0,3,6,4,2,6,8] 23 | Output: "832" 24 | Explanation: Replace the substring "1": 25 | - 1 maps to change[1] = 8. 26 | Thus, "132" becomes "832". 27 | "832" is the largest number that can be created, so return it. 28 | ``` 29 | **Example 2:** 30 | 31 | ``` 32 | Input: num = "021", change = [9,4,3,5,7,2,1,9,0,6] 33 | Output: "934" 34 | Explanation: Replace the substring "021": 35 | - 0 maps to change[0] = 9. 36 | - 2 maps to change[2] = 3. 37 | - 1 maps to change[1] = 4. 38 | Thus, "021" becomes "934". 39 | "934" is the largest number that can be created, so return it. 40 | ``` 41 | **Example 3:** 42 | 43 | ``` 44 | Input: num = "5", change = [1,4,7,5,3,2,5,6,9,4] 45 | Output: "5" 46 | Explanation: "5" is already the largest number that can be created, so return it. 47 | ``` 48 | 49 | 50 | **Constraints:** 51 | 52 | * `1 <= num.length <= 10^{5}` 53 | * `num` consists of only digits `0-9`. 54 | * `change.length == 10` 55 | * `0 <= change[d] <= 9` 56 | 57 | ## Solutions 58 | 59 | ```python 60 | class Solution: 61 | def maximumNumber(self, num: str, change: list[int]) -> str: # type: ignore 62 | num: list[str] = list(num) 63 | change: dict[str, str] = { 64 | str(i): str(d) for i, d in enumerate(change) if d >= i 65 | } 66 | mutating = False 67 | for i, d in enumerate(num): 68 | if d in change: 69 | num[i] = change[d] 70 | if change[d] > d and not mutating: 71 | mutating = True 72 | elif mutating: 73 | break 74 | return "".join(num) 75 | ``` 76 | 77 | Returns a string that is the largest possible integer after mutating a contiguos substring in the given string `num`. 78 | 79 | We notice that a digit at the front has more weight than those that follow it. 80 | So, starting from the left, we leave the digits unmutated until we a digit that has a mutation that is larger than itself (`d < change[d]`). 81 | Starting at this digit and going to the right, we mutate the following digits if their mutation is at least as big as themselves (`d <= change[d]`). 82 | As soon as we encounter a digit whose mutation is smaller than itself, we stop the mutation and continue adding the original digits. 83 | 84 | **Time Complexity**: `O(n)`, We iterate through the characters in the string of length `n`. 85 | **Space Complexity**: `O(1)`, We do not use any extra space. 86 | 87 | -------------------------------------------------------------------------------- /tests/test_extract_solution.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import os 3 | 4 | import pytest 5 | 6 | from leetscrape import ExtractSolutions 7 | 8 | 9 | def test_extract_solutions(): 10 | # Create an instance of ExtractSolutions 11 | extractor = ExtractSolutions("./tests/q_0009_palindromeNumber.py") 12 | 13 | # Test extracting solutions 14 | solutions = extractor.extract() 15 | assert len(solutions) == 2 # Update with the expected number of solutions 16 | assert isinstance(solutions[0].id, int) # Update with the expected type 17 | assert isinstance(solutions[0].code, str) # Update with the expected type 18 | assert isinstance(solutions[0].docs, dict) # Update with the expected type 19 | assert isinstance( 20 | solutions[0].problem_statement, str 21 | ) # Update with the expected type 22 | 23 | 24 | def test_to_mdx(): 25 | # Create an instance of ExtractSolutions 26 | extractor = ExtractSolutions("./tests/q_0009_palindromeNumber.py") 27 | 28 | # Test converting to mdx 29 | mdx = extractor.to_mdx() 30 | assert isinstance(mdx, str) # Update with the expected type 31 | 32 | 33 | def test_to_mdx_with_filename(): 34 | # Create an instance of ExtractSolutions 35 | extractor = ExtractSolutions("./tests/q_0009_palindromeNumber.py") 36 | 37 | # Test converting to mdx with filename 38 | extractor.to_mdx(output_filename="./tests/q_0009_palindromeNumber.mdx") 39 | # Add more assertions for the specific file path 40 | os.remove("./tests/q_0009_palindromeNumber.mdx") 41 | 42 | 43 | def test_extract_front_matter(): 44 | # Create an instance of ExtractSolutions 45 | extractor = ExtractSolutions("./tests/q_0009_palindromeNumber.py") 46 | 47 | # Test extracting front matter 48 | front_matter = extractor._extract_front_matter() 49 | assert isinstance(front_matter, dict) # Update with the expected type 50 | # Add more assertions for the specific keys and values in the front matter dictionary 51 | 52 | 53 | # Add more test cases as needed 54 | def test_extract_with_custom_top_class_name(): 55 | with pytest.raises(ValueError): 56 | # Create an instance of ExtractSolutions 57 | extractor = ExtractSolutions( 58 | "./tests/q_0009_palindromeNumber.py", 59 | ) 60 | 61 | # Test extracting solutions with custom top class name 62 | solutions = extractor.extract( 63 | top_class_name="CustomSolution", 64 | ) 65 | 66 | 67 | def test_extract_code_with_invalid_node(): 68 | # Create an instance of ExtractSolutions 69 | extractor = ExtractSolutions("./tests/q_0009_palindromeNumber.py") 70 | 71 | # Create an invalid node for testing 72 | node = ast.AsyncFunctionDef( 73 | name="test_function", 74 | args=ast.arguments(), 75 | body=[], 76 | lineno=None, 77 | end_lineno=None, 78 | ) 79 | 80 | # Test extracting code with invalid node 81 | with pytest.raises(ValueError): 82 | code = extractor._extract_code(node) 83 | # Add more assertions or error messages for the specific error case 84 | 85 | 86 | def test_non_dict_front_matter(): 87 | with pytest.raises(ValueError): 88 | # Create an instance of ExtractSolutions 89 | extractor = ExtractSolutions( 90 | "./tests/q_0009_palindromeNumber_wo_frontmatter.py" 91 | ) 92 | extractor.to_mdx() 93 | -------------------------------------------------------------------------------- /example/solutions/q_1946_largestNumberAfterMutatingSubstring.py: -------------------------------------------------------------------------------- 1 | front_matter = { 2 | "qid": 1946, 3 | "title": "Largest Number After Mutating Substring", 4 | "titleSlug": "largest-number-after-mutating-substring", 5 | "difficulty": "Medium", 6 | "tags": ["Array", "String", "Greedy"], 7 | } 8 | 9 | 10 | # ====================== DO NOT EDIT ABOVE THIS LINE ====================== 11 | class Solution: 12 | """You are given a string `num`, which represents a large integer. You are also given a **0-indexed** integer array `change` of length `10` that maps each digit `0-9` to another digit. More formally, digit `d` maps to digit `change[d]`. 13 | 14 | You may **choose** to **mutate a single substring** of `num`. To mutate a substring, replace each digit `num[i]` with the digit it maps to in `change` (i.e. replace `num[i]` with `change[num[i]]`). 15 | 16 | Return *a string representing the **largest** possible integer after **mutating** (or choosing not to) a **single substring** of* `num`. 17 | 18 | A **substring** is a contiguous sequence of characters within the string. 19 | 20 | 21 | 22 | **Example 1:** 23 | 24 | ``` 25 | Input: num = "132", change = [9,8,5,0,3,6,4,2,6,8] 26 | Output: "832" 27 | Explanation: Replace the substring "1": 28 | - 1 maps to change[1] = 8. 29 | Thus, "132" becomes "832". 30 | "832" is the largest number that can be created, so return it. 31 | ``` 32 | **Example 2:** 33 | 34 | ``` 35 | Input: num = "021", change = [9,4,3,5,7,2,1,9,0,6] 36 | Output: "934" 37 | Explanation: Replace the substring "021": 38 | - 0 maps to change[0] = 9. 39 | - 2 maps to change[2] = 3. 40 | - 1 maps to change[1] = 4. 41 | Thus, "021" becomes "934". 42 | "934" is the largest number that can be created, so return it. 43 | ``` 44 | **Example 3:** 45 | 46 | ``` 47 | Input: num = "5", change = [1,4,7,5,3,2,5,6,9,4] 48 | Output: "5" 49 | Explanation: "5" is already the largest number that can be created, so return it. 50 | ``` 51 | 52 | 53 | **Constraints:** 54 | 55 | * `1 <= num.length <= 10^{5}` 56 | * `num` consists of only digits `0-9`. 57 | * `change.length == 10` 58 | * `0 <= change[d] <= 9` 59 | """ 60 | 61 | def maximumNumber(self, num: str, change: list[int]) -> str: # type: ignore 62 | """Returns a string that is the largest possible integer after mutating a contiguos substring in the given string `num`. 63 | 64 | We notice that a digit at the front has more weight than those that follow it. 65 | So, starting from the left, we leave the digits unmutated until we a digit that has a mutation that is larger than itself (`d < change[d]`). 66 | Starting at this digit and going to the right, we mutate the following digits if their mutation is at least as big as themselves (`d <= change[d]`). 67 | As soon as we encounter a digit whose mutation is smaller than itself, we stop the mutation and continue adding the original digits. 68 | 69 | Args: 70 | num (str): The string to be mutated. 71 | change (list[int]): The mutations available. 72 | 73 | Returns: 74 | str: The largest mutated string. 75 | 76 | Time Complexity: 77 | `O(n)`: We iterate through the characters in the string of length `n`. 78 | 79 | Space Complexity: 80 | `O(1)`: We do not use any extra space. 81 | """ 82 | num: list[str] = list(num) 83 | change: dict[str, str] = { 84 | str(i): str(d) for i, d in enumerate(change) if d >= i 85 | } 86 | mutating = False 87 | for i, d in enumerate(num): 88 | if d in change: 89 | num[i] = change[d] 90 | if change[d] > d and not mutating: 91 | mutating = True 92 | elif mutating: 93 | break 94 | return "".join(num) 95 | 96 | # If you have multiple solutions, add them all here as methods of the same class. 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | *.ipynb 3 | !example/notebooks/package_usage.ipynb 4 | __pycache__ 5 | 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | *.py,cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | cover/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | local_settings.py 66 | db.sqlite3 67 | db.sqlite3-journal 68 | 69 | # Flask stuff: 70 | instance/ 71 | .webassets-cache 72 | 73 | # Scrapy stuff: 74 | .scrapy 75 | 76 | # Sphinx documentation 77 | docs/_build/ 78 | 79 | # PyBuilder 80 | .pybuilder/ 81 | target/ 82 | 83 | # Jupyter Notebook 84 | .ipynb_checkpoints 85 | 86 | # IPython 87 | profile_default/ 88 | ipython_config.py 89 | 90 | # pyenv 91 | # For a library or package, you might want to ignore these files since the code is 92 | # intended to run in multiple environments; otherwise, check them in: 93 | # .python-version 94 | 95 | # pipenv 96 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 97 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 98 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 99 | # install all needed dependencies. 100 | #Pipfile.lock 101 | 102 | # poetry 103 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 104 | # This is especially recommended for binary packages to ensure reproducibility, and is more 105 | # commonly ignored for libraries. 106 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 107 | #poetry.lock 108 | 109 | # pdm 110 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 111 | #pdm.lock 112 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 113 | # in version control. 114 | # https://pdm.fming.dev/#use-with-ide 115 | .pdm.toml 116 | 117 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 118 | __pypackages__/ 119 | 120 | # Celery stuff 121 | celerybeat-schedule 122 | celerybeat.pid 123 | 124 | # SageMath parsed files 125 | *.sage.py 126 | 127 | # Environments 128 | .env 129 | .venv 130 | env/ 131 | venv/ 132 | ENV/ 133 | env.bak/ 134 | venv.bak/ 135 | 136 | # Spyder project settings 137 | .spyderproject 138 | .spyproject 139 | 140 | # Rope project settings 141 | .ropeproject 142 | 143 | # mkdocs documentation 144 | /site 145 | 146 | # mypy 147 | .mypy_cache/ 148 | .dmypy.json 149 | dmypy.json 150 | 151 | # Pyre type checker 152 | .pyre/ 153 | 154 | # pytype static type analyzer 155 | .pytype/ 156 | 157 | # Cython debug symbols 158 | cython_debug/ 159 | 160 | # PyCharm 161 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 162 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 163 | # and can be added to the global gitignore or merged into this file. For a more nuclear 164 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 165 | #.idea/ 166 | 167 | 168 | */sql/insert.sql 169 | example/data_test/ 170 | tests/reports 171 | tests/data 172 | codecov.exe -------------------------------------------------------------------------------- /src/leetscrape/_constants.py: -------------------------------------------------------------------------------- 1 | # List of problem categories 2 | CATEGORIES = [ 3 | {"slug": "algorithms", "name": "Algorithms"}, 4 | {"slug": "database", "name": "Database"}, 5 | {"slug": "shell", "name": "Shell"}, 6 | {"slug": "concurrency", "name": "Concurrency"}, 7 | ] 8 | 9 | # List of topic tags 10 | TOPIC_TAGS = [ 11 | {"slug": "array", "name": "Array"}, 12 | {"slug": "string", "name": "String"}, 13 | {"slug": "hash-table", "name": "Hash Table"}, 14 | {"slug": "dynamic-programming", "name": "Dynamic Programming"}, 15 | {"slug": "math", "name": "Math"}, 16 | {"slug": "sorting", "name": "Sorting"}, 17 | {"slug": "greedy", "name": "Greedy"}, 18 | {"slug": "depth-first-search", "name": "Depth-First Search"}, 19 | {"slug": "database", "name": "Database"}, 20 | {"slug": "breadth-first-search", "name": "Breadth-First Search"}, 21 | {"slug": "binary-search", "name": "Binary Search"}, 22 | {"slug": "tree", "name": "Tree"}, 23 | {"slug": "matrix", "name": "Matrix"}, 24 | {"slug": "binary-tree", "name": "Binary Tree"}, 25 | {"slug": "two-pointers", "name": "Two Pointers"}, 26 | {"slug": "bit-manipulation", "name": "Bit Manipulation"}, 27 | {"slug": "stack", "name": "Stack"}, 28 | {"slug": "heap-priority-queue", "name": "Heap (Priority Queue)"}, 29 | {"slug": "design", "name": "Design"}, 30 | {"slug": "graph", "name": "Graph"}, 31 | {"slug": "prefix-sum", "name": "Prefix Sum"}, 32 | {"slug": "simulation", "name": "Simulation"}, 33 | {"slug": "counting", "name": "Counting"}, 34 | {"slug": "backtracking", "name": "Backtracking"}, 35 | {"slug": "sliding-window", "name": "Sliding Window"}, 36 | {"slug": "union-find", "name": "Union Find"}, 37 | {"slug": "linked-list", "name": "Linked List"}, 38 | {"slug": "ordered-set", "name": "Ordered Set"}, 39 | {"slug": "monotonic-stack", "name": "Monotonic Stack"}, 40 | {"slug": "enumeration", "name": "Enumeration"}, 41 | {"slug": "recursion", "name": "Recursion"}, 42 | {"slug": "trie", "name": "Trie"}, 43 | {"slug": "divide-and-conquer", "name": "Divide and Conquer"}, 44 | {"slug": "binary-search-tree", "name": "Binary Search Tree"}, 45 | {"slug": "bitmask", "name": "Bitmask"}, 46 | {"slug": "queue", "name": "Queue"}, 47 | {"slug": "memoization", "name": "Memoization"}, 48 | {"slug": "geometry", "name": "Geometry"}, 49 | {"slug": "segment-tree", "name": "Segment Tree"}, 50 | {"slug": "topological-sort", "name": "Topological Sort"}, 51 | {"slug": "number-theory", "name": "Number Theory"}, 52 | {"slug": "hash-function", "name": "Hash Function"}, 53 | {"slug": "binary-indexed-tree", "name": "Binary Indexed Tree"}, 54 | {"slug": "game-theory", "name": "Game Theory"}, 55 | {"slug": "data-stream", "name": "Data Stream"}, 56 | {"slug": "interactive", "name": "Interactive"}, 57 | {"slug": "string-matching", "name": "String Matching"}, 58 | {"slug": "rolling-hash", "name": "Rolling Hash"}, 59 | {"slug": "shortest-path", "name": "Shortest Path"}, 60 | {"slug": "combinatorics", "name": "Combinatorics"}, 61 | {"slug": "randomized", "name": "Randomized"}, 62 | {"slug": "brainteaser", "name": "Brainteaser"}, 63 | {"slug": "monotonic-queue", "name": "Monotonic Queue"}, 64 | {"slug": "merge-sort", "name": "Merge Sort"}, 65 | {"slug": "iterator", "name": "Iterator"}, 66 | {"slug": "concurrency", "name": "Concurrency"}, 67 | {"slug": "doubly-linked-list", "name": "Doubly-Linked List"}, 68 | {"slug": "probability-and-statistics", "name": "Probability and Statistics"}, 69 | {"slug": "quickselect", "name": "Quickselect"}, 70 | {"slug": "bucket-sort", "name": "Bucket Sort"}, 71 | {"slug": "suffix-array", "name": "Suffix Array"}, 72 | {"slug": "minimum-spanning-tree", "name": "Minimum Spanning Tree"}, 73 | {"slug": "counting-sort", "name": "Counting Sort"}, 74 | {"slug": "shell", "name": "Shell"}, 75 | {"slug": "line-sweep", "name": "Line Sweep"}, 76 | {"slug": "reservoir-sampling", "name": "Reservoir Sampling"}, 77 | {"slug": "eulerian-circuit", "name": "Eulerian Circuit"}, 78 | {"slug": "radix-sort", "name": "Radix Sort"}, 79 | {"slug": "strongly-connected-component", "name": "Strongly Connected Component"}, 80 | {"slug": "rejection-sampling", "name": "Rejection Sampling"}, 81 | {"slug": "biconnected-component", "name": "Biconnected Component"}, 82 | ] 83 | 84 | NO_PYTHON_STUB = "# This question has no Python code stub.\n# Generating a generic Python code stub\nclass Solution:\n def {}(self) -> Any:\n " 85 | PREMIUM_CUSTOMER_PYTHON_STUB = "# This questions is only for paid Leetcode subscribers.\n# Generating a generic Python code stub\nclass Solution:\n def {}(self) -> Any:\n " 86 | 87 | HEADERS = { 88 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36" 89 | } 90 | -------------------------------------------------------------------------------- /example/notebooks/package_usage.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "Scrape Questions and metadata\n" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "from leetscrape import GetQuestionsList, GetQuestion" 18 | ] 19 | }, 20 | { 21 | "attachments": {}, 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "Query the question list\n" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 3, 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "name": "stdout", 35 | "output_type": "stream", 36 | "text": [ 37 | "Scraping companies ... Done\n", 38 | "Scraping questions list ... Done\n", 39 | "Extracting question topics ... Done\n", 40 | "Getting Categories ... Done\n", 41 | "Scraping Topic Tags ... Done\n", 42 | "Extracting question category ... Done\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "ls = GetQuestionsList()\n", 48 | "ls.scrape() # Scrape the list of questions\n", 49 | "ls.to_csv(directory=\"../data_test/\") # Save the scraped tables to a directory\n" 50 | ] 51 | }, 52 | { 53 | "attachments": {}, 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "Query Individual question info such as the body, test cases, constraints, hints, code stubs, etc.\n" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 9, 63 | "metadata": {}, 64 | "outputs": [ 65 | { 66 | "name": "stderr", 67 | "output_type": "stream", 68 | "text": [ 69 | "D:\\code\\python\\LeetScrape\\src\\leetscrape\\question.py:106: UserWarning: This questions is only for paid Leetcode subscribers.\n", 70 | " warnings.warn(\"This questions is only for paid Leetcode subscribers.\")\n", 71 | "D:\\code\\python\\LeetScrape\\src\\leetscrape\\question.py:143: UserWarning: This questions is only for paid Leetcode subscribers.\n", 72 | " warnings.warn(\"This questions is only for paid Leetcode subscribers.\")\n" 73 | ] 74 | }, 75 | { 76 | "data": { 77 | "text/plain": [ 78 | "487. max-consecutive-ones-ii\n", 79 | "This questions is only for paid Leetcode subscribers.SimilarQuestions: [485, 1004, 2155]" 80 | ] 81 | }, 82 | "execution_count": 9, 83 | "metadata": {}, 84 | "output_type": "execute_result" 85 | } 86 | ], 87 | "source": [ 88 | "qi = GetQuestion(titleSlug=\"max-consecutive-ones-ii\")\n", 89 | "qi.scrape()" 90 | ] 91 | }, 92 | { 93 | "attachments": {}, 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "Generate questions and test cases" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 10, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "name": "stdout", 107 | "output_type": "stream", 108 | "text": [ 109 | "Generating code stub for 487. max-consecutive-ones-ii\n", 110 | "Code stub save to q_0487_maxConsecutiveOnesIi.py\n" 111 | ] 112 | }, 113 | { 114 | "name": "stderr", 115 | "output_type": "stream", 116 | "text": [ 117 | "D:\\code\\python\\LeetScrape\\src\\leetscrape\\question.py:106: UserWarning: This questions is only for paid Leetcode subscribers.\n", 118 | " warnings.warn(\"This questions is only for paid Leetcode subscribers.\")\n", 119 | "D:\\code\\python\\LeetScrape\\src\\leetscrape\\question.py:143: UserWarning: This questions is only for paid Leetcode subscribers.\n", 120 | " warnings.warn(\"This questions is only for paid Leetcode subscribers.\")\n" 121 | ] 122 | } 123 | ], 124 | "source": [ 125 | "from leetscrape import GenerateCodeStub\n", 126 | "\n", 127 | "fcs = GenerateCodeStub(qid=487)\n", 128 | "fcs.generate()" 129 | ] 130 | }, 131 | { 132 | "attachments": {}, 133 | "cell_type": "markdown", 134 | "metadata": {}, 135 | "source": [ 136 | "Extract solutions from py file and upload them to the database" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 3, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "from leetscrape import ExtractSolutions" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 4, 151 | "metadata": {}, 152 | "outputs": [], 153 | "source": [ 154 | "es = ExtractSolutions(\"../solutions/q_0009_palindromeNumber.py\")\n", 155 | "sols = es.extract()\n", 156 | "es.to_mdx(\"../solutions/q_0009_palindromeNumber.md\")" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [] 165 | } 166 | ], 167 | "metadata": { 168 | "kernelspec": { 169 | "display_name": ".venv", 170 | "language": "python", 171 | "name": "python3" 172 | }, 173 | "language_info": { 174 | "codemirror_mode": { 175 | "name": "ipython", 176 | "version": 3 177 | }, 178 | "file_extension": ".py", 179 | "mimetype": "text/x-python", 180 | "name": "python", 181 | "nbconvert_exporter": "python", 182 | "pygments_lexer": "ipython3", 183 | "version": "3.10.13" 184 | }, 185 | "orig_nbformat": 4, 186 | "vscode": { 187 | "interpreter": { 188 | "hash": "b3f3b27324d3dffefcfe684ee5f63d23987742678b59d2ebc9e4a131ef9fcba7" 189 | } 190 | } 191 | }, 192 | "nbformat": 4, 193 | "nbformat_minor": 2 194 | } 195 | -------------------------------------------------------------------------------- /src/leetscrape/question.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | import warnings 4 | 5 | import pandas as pd 6 | import requests 7 | 8 | from ._constants import HEADERS, NO_PYTHON_STUB, PREMIUM_CUSTOMER_PYTHON_STUB 9 | from ._helper import camel_case 10 | from .models import Question 11 | 12 | # Leetcode's graphql api endpoint 13 | BASE_URL = "https://leetcode.com/graphql" 14 | 15 | 16 | class GetQuestion: 17 | """ 18 | A class to acquire the statement, constraints, hints, basic test cases, related questions, and code stubs of the given question. 19 | 20 | Args: 21 | titleSlug (str): The title slug of the question. 22 | """ 23 | 24 | def __init__(self, titleSlug: str): 25 | self.titleSlug = titleSlug 26 | self.questions_info = self.fetch_all_questions_id_and_stub() 27 | 28 | @staticmethod 29 | def fetch_all_questions_id_and_stub(): 30 | req = requests.get( 31 | "https://leetcode.com/api/problems/all/", headers=HEADERS 32 | ).json() 33 | question_data = pd.json_normalize(req["stat_status_pairs"]).rename( 34 | columns={ 35 | "stat.frontend_question_id": "QID", 36 | "stat.question__title_slug": "titleSlug", 37 | } 38 | )[["QID", "titleSlug"]] 39 | 40 | return question_data.sort_values("QID").set_index("titleSlug") 41 | 42 | def scrape(self) -> Question: 43 | """This method calls the Leetcode graphql api to query for the hints, companyTags (currently returning null as this is a premium feature), code snippets, and content of the question. 44 | 45 | Raises: 46 | ValueError: When the connection to Leetcode's graphql api is not established. 47 | 48 | Returns: 49 | QuestionInfo: Contains the QID, titleSlug, Hints, Companies, Similar Questions, Code stubs, and the body of the question. 50 | """ 51 | data = { 52 | "query": """query questionHints($titleSlug: String!) { 53 | question(titleSlug: $titleSlug) { 54 | questionFrontendId 55 | title 56 | hints 57 | difficulty 58 | companyTags { 59 | name 60 | slug 61 | imgUrl 62 | } 63 | topicTags { 64 | name 65 | } 66 | similarQuestions 67 | codeSnippets { 68 | lang 69 | langSlug 70 | code 71 | } 72 | content 73 | isPaidOnly 74 | } 75 | } 76 | """, 77 | "variables": {"titleSlug": self.titleSlug}, 78 | } 79 | response = requests.post(BASE_URL, json=data) 80 | if response.status_code == 404: 81 | raise ValueError("Leetcode's graphql API can't be found.") 82 | while response.status_code == 429 | 400: 83 | time.sleep(10) 84 | response = requests.post(BASE_URL, json=data) 85 | if response.status_code == 404: 86 | raise ValueError("Leetcode's graphql API can't be found.") 87 | response = response.json() 88 | return Question( 89 | QID=response["data"]["question"]["questionFrontendId"], 90 | title=response["data"]["question"]["title"], 91 | titleSlug=self.titleSlug, 92 | difficulty=response["data"]["question"]["difficulty"], 93 | Hints=response["data"]["question"]["hints"], 94 | Companies=response["data"]["question"]["companyTags"], 95 | topics=[ 96 | topic["name"] for topic in response["data"]["question"]["topicTags"] 97 | ], 98 | isPaidOnly=response["data"]["question"]["isPaidOnly"], 99 | Body=self._get_question_body(response), 100 | Code=self._get_code_snippet(response), 101 | SimilarQuestions=self._get_similar_questions(response), 102 | ) 103 | 104 | def _get_question_body(self, response) -> str: # type: ignore 105 | if not response["data"]["question"]["isPaidOnly"]: 106 | return response["data"]["question"]["content"] 107 | else: 108 | warnings.warn("This questions is only for paid Leetcode subscribers.") 109 | return "This questions is only for paid Leetcode subscribers." 110 | 111 | # Similar questions 112 | def _get_similar_questions(self, response) -> list[int]: 113 | """A helper method to extract the list of similar questions of the 114 | given question. 115 | 116 | Returns: 117 | list[int]: The list of QIDs of the questions similar to the given question. 118 | """ 119 | similar_questions = [] 120 | for qs in json.loads(response["data"]["question"]["similarQuestions"]): 121 | similar_questions.append(self.questions_info.loc[qs["titleSlug"]].QID) 122 | return similar_questions 123 | 124 | # Code Snippet 125 | def _get_code_snippet(self, response) -> str: # type: ignore 126 | """A helper method to extract the code snippets from the query response. 127 | Currently, this method returns the Python3 code snippet if available, 128 | else it returns a barebones Python3 code snippet with the class name and 129 | method named after the titleSlug. 130 | 131 | Returns: 132 | str: Python3 code snippet 133 | """ 134 | if not response["data"]["question"]["isPaidOnly"]: 135 | python_code_snippet = [ 136 | code_snippet 137 | for code_snippet in response["data"]["question"]["codeSnippets"] 138 | if code_snippet["langSlug"] == "python3" 139 | ] 140 | if len(python_code_snippet) > 0: 141 | return python_code_snippet[0]["code"] 142 | else: 143 | return NO_PYTHON_STUB.format(camel_case(self.titleSlug)) 144 | else: 145 | warnings.warn("This questions is only for paid Leetcode subscribers.") 146 | return PREMIUM_CUSTOMER_PYTHON_STUB.format(camel_case(self.titleSlug)) 147 | -------------------------------------------------------------------------------- /src/leetscrape/scripts.py: -------------------------------------------------------------------------------- 1 | def leetscrape_list(args, parser): 2 | from . import GetQuestion 3 | 4 | df = GetQuestion.fetch_all_questions_id_and_stub() 5 | if args.out: 6 | # Save the DataFrame to the specified file 7 | df.to_csv(args.out) 8 | print(f"DataFrame saved to {args.out}") 9 | else: 10 | # Print the DataFrame to the console 11 | print(df.to_string()) 12 | 13 | 14 | def leetscrape_question(args, parser): 15 | from . import GenerateCodeStub 16 | 17 | if not args.qid: 18 | parser.error("Question ID(s) need to be specified.") 19 | for qid in args.qid: 20 | fcs = GenerateCodeStub(qid=qid) 21 | fcs.generate( 22 | directory=args.out if args.out else ".", 23 | ) 24 | 25 | 26 | def leetscrape_solution(args, parser): 27 | import os 28 | 29 | from . import ExtractSolutions 30 | 31 | if not args.input: 32 | parser.error("Input needs to be specified.") 33 | output_dir = args.out if args.out else "." 34 | # Create the output directory if it doesn't exist 35 | if not os.path.exists(output_dir): 36 | os.makedirs(output_dir) 37 | 38 | # Check if input is a directory or a file 39 | if os.path.isdir(args.input): 40 | import glob 41 | import os 42 | 43 | from tqdm import tqdm 44 | 45 | # Get all py files in the specified directory which start with "q_" 46 | solution_files = glob.glob(os.path.join(args.input, "q_*.py")) 47 | print(f"Found {len(solution_files)} solution files in {args.input}") 48 | for solution_file in tqdm(solution_files): 49 | file_name = os.path.basename(solution_file).split(".py")[0] 50 | # create output file name 51 | output_file_name = os.path.join(output_dir, file_name + ".mdx") 52 | ExtractSolutions(solution_file).to_mdx(output_filename=output_file_name) 53 | print(f"Saved {len(solution_files)} solution files to {output_dir}") 54 | elif os.path.isfile(args.input): 55 | file_name = os.path.basename(args.input).split(".py")[0] 56 | output_file_name = os.path.join(output_dir, file_name + ".mdx") 57 | ExtractSolutions(args.input).to_mdx(output_filename=output_file_name) 58 | print(f"Saved solution file to {output_file_name}") 59 | 60 | 61 | def leetscrape_ts(args, parser): 62 | import subprocess 63 | 64 | subprocess.run( 65 | [ 66 | "npx", 67 | "create-next-app@latest", 68 | args.out if args.out else "leetscrape-ts", 69 | "-e", 70 | "https://github.com/nikhil-ravi/leetscrape-ts", 71 | ], 72 | shell=True, 73 | ) 74 | 75 | 76 | def leetscrape(): 77 | import argparse 78 | 79 | parser = argparse.ArgumentParser( 80 | description="Run this script to interact with the leetscrape package." 81 | ) 82 | subparsers = parser.add_subparsers( 83 | title="subcommands", dest="subcommand", help="sub-command help" 84 | ) 85 | 86 | # Subcommand for listing questions 87 | parser_list = subparsers.add_parser( 88 | "list", 89 | help="List all questions without generating code stub", 90 | description="List all questions without generating code stub", 91 | ) 92 | parser_list.add_argument( 93 | "--out", 94 | "-o", 95 | # metavar="Output file name", 96 | type=str, 97 | help="Specify the output file name to store the list of questions.", 98 | required=False, 99 | ) 100 | parser_list.set_defaults(func=leetscrape_list) 101 | 102 | # Subcommand for generating code stub 103 | parser_question = subparsers.add_parser( 104 | "question", 105 | help="Generate a code stub for the given question", 106 | description="Generate a code stub for the given question", 107 | ) 108 | parser_question.add_argument( 109 | "qid", 110 | # metavar="Question ID", 111 | nargs="+", 112 | type=int, 113 | help="Enter Leetcode question ID(s) (e.g. 1 2 3)", 114 | ) 115 | parser_question.add_argument( 116 | "--out", 117 | "-o", 118 | # metavar="Output directory", 119 | type=str, 120 | help="Enter the path to the output directory", 121 | required=False, 122 | ) 123 | parser_question.set_defaults(func=leetscrape_question) 124 | 125 | # Subcommand for generating mdx files for solutions 126 | parser_solution = subparsers.add_parser( 127 | "solution", 128 | help="Generate mdx files for solutions", 129 | description="Generate mdx files for solutions", 130 | ) 131 | parser_solution.add_argument( 132 | "input", 133 | # metavar="Solution directory", 134 | type=str, 135 | help="Enter the path to the solution directory with solution files or to a single solution file", 136 | ) 137 | parser_solution.add_argument( 138 | "--out", 139 | "-o", 140 | # metavar="Output directory", 141 | type=str, 142 | help="Enter the path to the output directory to save solutions mdx files", 143 | required=False, 144 | ) 145 | parser_solution.set_defaults(func=leetscrape_solution) 146 | 147 | # Subcommand for creating the leetscrape-ts Next.js project to host the solutions 148 | parser_ts = subparsers.add_parser( 149 | "ts", 150 | help="Create the leetscrape-ts Next.js project to host the solutions", 151 | description="Create the leetscrape-ts Next.js project to host the solutions", 152 | ) 153 | parser_ts.add_argument( 154 | "--out", 155 | "-o", 156 | # metavar="Output directory", 157 | type=str, 158 | help="Enter the path to the output directory to save the project", 159 | required=False, 160 | ) 161 | parser_ts.set_defaults(func=leetscrape_ts) 162 | 163 | args = parser.parse_args() 164 | args.func(args, parser) 165 | 166 | 167 | def leetupload_solution(): 168 | import argparse 169 | 170 | # This script is deprecated and will be removed in the next release. 171 | parser = argparse.ArgumentParser( 172 | description="Run this script to upload the solutions to the leetscrape-ts project. DEPRECATED!" 173 | ) 174 | parser.error( 175 | "This script is deprecated and will be removed in the next release. Please use `leetscrape ts --help` instead for serving your files on the web." 176 | ) 177 | -------------------------------------------------------------------------------- /example/data/companies.csv: -------------------------------------------------------------------------------- 1 | name,slug,questionCount 2 | Google,google,1203 3 | Bloomberg,bloomberg,561 4 | Facebook,facebook,658 5 | Apple,apple,600 6 | Microsoft,microsoft,710 7 | Cisco,cisco,69 8 | Adobe,adobe,507 9 | Uber,uber,428 10 | Oracle,oracle,218 11 | Salesforce,salesforce,120 12 | TikTok,tiktok,224 13 | Yandex,yandex,90 14 | JPMorgan,jpmorgan,65 15 | Amazon,amazon,1247 16 | Walmart Labs,walmart-labs,121 17 | Goldman Sachs,goldman-sachs,169 18 | Atlassian,atlassian,35 19 | Snapchat,snapchat,115 20 | PayPal,paypal,73 21 | DE Shaw,de-shaw,51 22 | eBay,ebay,66 23 | Tesla,tesla,43 24 | Citadel,citadel,37 25 | tcs,tcs,47 26 | ByteDance,bytedance,139 27 | Nvidia,nvidia,50 28 | DoorDash,doordash,75 29 | Databricks,databricks,19 30 | LinkedIn,linkedin,166 31 | VMware,vmware,103 32 | Airbnb,airbnb,59 33 | Roblox,roblox,20 34 | Yahoo,yahoo,183 35 | Square,square,31 36 | Pinterest,pinterest,30 37 | ServiceNow,servicenow,43 38 | Flipkart,flipkart,46 39 | Samsung,samsung,62 40 | Visa,visa,66 41 | MathWorks,mathworks,25 42 | Nutanix,nutanix,32 43 | Infosys,infosys,55 44 | IBM,ibm,35 45 | Netflix,netflix,15 46 | Morgan Stanley,morgan-stanley,41 47 | BlackRock,blackrock,10 48 | SAP,sap,24 49 | Intuit,intuit,56 50 | Dropbox,dropbox,25 51 | Capital One,capital-one,21 52 | Two Sigma,two-sigma,15 53 | Accenture,accenture,22 54 | Cruise Automation,cruise-automation,21 55 | Expedia,expedia,79 56 | Palantir Technologies,palantir-technologies,25 57 | Intel,intel,31 58 | Docusign,docusign,22 59 | Jane Street,jane-street,7 60 | Spotify,spotify,27 61 | Lyft,lyft,29 62 | Zillow,zillow,37 63 | Coursera,coursera,11 64 | Qualcomm,qualcomm,25 65 | Splunk,splunk,15 66 | Zoho,zoho,20 67 | Deutsche Bank,deutsche-bank,8 68 | Booking.com,bookingcom,19 69 | Wix,wix,37 70 | Twitter,twitter,93 71 | Paytm,paytm,23 72 | HRT,hrt,22 73 | Stripe,stripe,2 74 | PhonePe,phonepe,26 75 | Coinbase,coinbase,13 76 | Juspay,juspay,5 77 | Hudson River Trading,hudson-river-trading,7 78 | Huawei,huawei,11 79 | Coupang,coupang,17 80 | Yelp,yelp,26 81 | Qualtrics,qualtrics,58 82 | Media.net,medianet,22 83 | instacart,instacart,7 84 | Arcesium,arcesium,26 85 | Robinhood,robinhood,13 86 | Sprinklr,sprinklr,22 87 | Karat,karat,20 88 | Akuna Capital,akuna-capital,23 89 | Rubrik,rubrik,21 90 | Wayfair,wayfair,32 91 | Affirm,affirm,7 92 | Citrix,citrix,8 93 | C3 IoT,c3-iot,16 94 | American Express,american-express,26 95 | Twilio,twilio,26 96 | Alibaba,alibaba,5 97 | GoDaddy,godaddy,11 98 | Epic Systems,epic-systems,6 99 | Arista Networks,arista-networks,16 100 | Deloitte,deloitte,5 101 | Barclays,barclays,3 102 | Cohesity,cohesity,7 103 | Jump Trading,jump-trading,3 104 | Twitch,twitch,20 105 | MakeMyTrip,makemytrip,18 106 | Zynga,zynga,3 107 | EPAM Systems,epam-systems,10 108 | Riot Games,riot-games,3 109 | Confluent,confluent,3 110 | Grab,grab,18 111 | Tencent,tencent,2 112 | Cognizant,cognizant,8 113 | Capgemini,capgemini,7 114 | razorpay,razorpay,3 115 | Dell,dell,7 116 | Hotstar,hotstar,12 117 | Nagarro,nagarro,15 118 | Codenation,codenation,9 119 | Siemens,siemens,3 120 | Duolingo,duolingo,6 121 | ShareChat,sharechat,10 122 | Asana,asana,5 123 | ZScaler,zscaler,5 124 | Point72,point72,5 125 | BNY Mellon,bny-mellon,6 126 | Bolt,bolt,11 127 | LiveRamp,liveramp,7 128 | Akamai,akamai,2 129 | Reddit,reddit,11 130 | Box,box,4 131 | Electronic Arts,electronic-arts,1 132 | Airtel,airtel,3 133 | Zoom,zoom,14 134 | FactSet,factset,8 135 | GE Digital,ge-digital,1 136 | Optum,optum,3 137 | Virtu Financial,virtu,7 138 | DRW,drw,6 139 | Activision,activision,2 140 | Pure Storage,pure-storage,3 141 | Mercari,mercari,7 142 | Audible,audible,10 143 | opentext,opentext,1 144 | Toptal,toptal,3 145 | Zomato,zomato,7 146 | Sony,sony,1 147 | persistent systems,persistent-systems,3 148 | Lowe,lowe,2 149 | McKinsey,mckinsey,6 150 | PayPay,paypay,2 151 | athenahealth,athenahealth,5 152 | Indeed,indeed,29 153 | Baidu,baidu,10 154 | Shopee,shopee,25 155 | InMobi,inmobi,3 156 | GE Healthcare,ge-healthcare,1 157 | payu,payu,3 158 | Tableau,tableau,3 159 | Groupon,groupon,5 160 | Accolite,accolite,10 161 | Quora,quora,25 162 | Veritas,veritas,2 163 | Tiger Analytics,tiger-analytics,2 164 | fourkites,fourkites,1 165 | Trilogy,trilogy,5 166 | Directi,directi,9 167 | Commvault,commvault,3 168 | Clari,clari,2 169 | Opendoor,opendoor,4 170 | Vimeo,vimeo,1 171 | Navi,navi,4 172 | Swiggy,swiggy,13 173 | Honeywell,honeywell,1 174 | Houzz,houzz,4 175 | Cashfree,cashfree,4 176 | Myntra,myntra,5 177 | Quip (Salesforce),quip,3 178 | TripAdvisor,tripadvisor,2 179 | IXL,ixl,13 180 | MAQ Software,maq-software,1 181 | Valve,valve,1 182 | MindTree,mindtree,2 183 | Snapdeal,snapdeal,3 184 | Sumologic,sumologic,7 185 | AppDynamics,appdynamics,4 186 | TuSimple,tusimple,14 187 | Info Edge,info-edge,2 188 | Millennium,millennium,1 189 | Thomson Reuters,thomson-reuters,2 190 | Code Studio,code-studio,1 191 | United Health Group,united-health-group,2 192 | Pony.ai,ponyai,5 193 | Hulu,hulu,8 194 | Dataminr,dataminr,3 195 | Sapient,sapient,2 196 | Lending Club,lending-club,1 197 | Kakao,kakao,2 198 | Garena,garena,1 199 | zeta suite,zeta-suite,1 200 | FPT,fpt,1 201 | National Instruments,national-instruments,5 202 | BitGo,bitgo,2 203 | Pocket Gems,pocket-gems,15 204 | Zendesk,zendesk,2 205 | IIT Bombay,iit-bombay,1 206 | AQR Capital Management LLC,aqr-capital-management-llc,2 207 | Yatra,yatra,1 208 | Societe Generale,societe-generale,2 209 | Cloudera,cloudera,6 210 | Wish,wish,20 211 | HBO,hbo,7 212 | Wealthfront,wealthfront,1 213 | Dunzo,dunzo,18 214 | Alation,alation,3 215 | Discord,discord,1 216 | Mindtickle,mindtickle,10 217 | Lucid,lucid,4 218 | Zenefits,zenefits,22 219 | Fallible,fallible,1 220 | Machine Zone,machine-zone,2 221 | Rackspace,rackspace,1 222 | Aetion,aetion,1 223 | Altimetrik,altimetrik,1 224 | observe.ai,observeai,1 225 | Works Applications,works-applications,4 226 | NetEase,netease,2 227 | Avalara,avalara,2 228 | CoderByte,coderbyte,1 229 | warnermedia,warnermedia,1 230 | Redfin,redfin,5 231 | Canonical,canonical,2 232 | Wayve,wayve,1 233 | Zappos,zappos,1 234 | Postmates,postmates,3 235 | instagram,instagram,1 236 | Radius,radius,1 237 | Fleetx,fleetx,1 238 | Poshmark,poshmark,5 239 | Drawbridge,drawbridge,1 240 | TripleByte,triplebyte,1 241 | Gilt Groupe,gilt-groupe,1 242 | ForUsAll,forusall,1 243 | epiFi,epifi,4 244 | Helix,helix,1 245 | Netsuite,netsuite,2 246 | SoundHound,soundhound,2 247 | Jingchi,jingchi,1 248 | Poynt,poynt,1 249 | TIAA,tiaa,1 250 | GSN Games,gsn-games,5 251 | Zopsmart,zopsmart,2 252 | Bridgewater Associates,bridgewater-associates,1 253 | Affinity,affinity,1 254 | alphonso,alphonso,1 255 | Moengage,moengage,1 256 | Strava,strava,1 257 | T-mobile,t-mobiles,1 258 | Softwire,softwire,2 259 | general electric,general-electric,1 260 | codeagon,codeagon,1 261 | Quince,quince,1 262 | DailyHunt,dailyhunt,1 263 | NextJump,nextjump,1 264 | Mobisy,mobisy,1 265 | MishiPay,mishipay,1 266 | Leap Motion,leap-motion,1 267 | Xing,xing,1 268 | RetailMeNot,retailmenot,1 269 | Analytics quotient,analytics-quotient,2 270 | Ascend,ascend,1 271 | AllinCall,allincall,1 272 | Pickrr,pickrr,1 273 | T System,t-system,1 274 | Unbxd,unbxd,1 275 | MachineZone,machinezone,1 276 | edabit,edabit,1 277 | Jeavio,jeavio,1 278 | -------------------------------------------------------------------------------- /src/leetscrape/extract_solution.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | from docstring_parser.google import DEFAULT_SECTIONS, GoogleParser, Section, SectionType 4 | 5 | from .models import Solution 6 | 7 | 8 | class ExtractSolutions: 9 | def __init__(self, filename: str): 10 | self.filename = filename 11 | with open(self.filename) as fd: 12 | file_contents = fd.read() 13 | self.module = ast.parse(file_contents) 14 | self.solutions = None 15 | 16 | def extract(self, top_class_name: str = "Solution") -> list[Solution]: 17 | """ 18 | Extract solutions from a given python file. 19 | 20 | Args: 21 | filename (str): The path of the file to extract solutions from. This python script should have the solution method(s) in the class named in the top_class-name. 22 | top_class_name (str, optional): The name of the class from which to extract the solutions from. Defaults to `Solution'. 23 | 24 | Raises: 25 | ValueError: When the filename does not follow the required convention of `q_{{LEETCODE_QID}}_ {{LEETCODE_TITLE}}.py`. 26 | ValueError: When the provided python file does not have a class named Solution. 27 | 28 | Returns: 29 | list[Solution]: A list of solutions, each containing an id, code [and docs]. 30 | """ 31 | 32 | class_definition = [ 33 | node 34 | for node in self.module.body 35 | if isinstance(node, ast.ClassDef) and node.name == top_class_name 36 | ] 37 | if not class_definition: 38 | raise ValueError( 39 | "The provided python file should have a class named Solution." 40 | ) 41 | method_definitions = [ 42 | node 43 | for node in class_definition[0].body 44 | if isinstance(node, ast.FunctionDef) 45 | ] 46 | 47 | self.solutions = [ 48 | Solution( 49 | id=idx + 1, 50 | code=self._extract_code(f), 51 | docs=parse_method_docstring(ast.get_docstring(f, clean=True)), 52 | problem_statement=ast.get_docstring(class_definition[0], clean=True), 53 | ) 54 | for idx, f in enumerate(method_definitions) 55 | ] 56 | 57 | return self.solutions 58 | 59 | def to_mdx(self, output_filename: str | None = None) -> str: 60 | if self.solutions is None: 61 | self.extract() 62 | front_matter = self._extract_front_matter() 63 | # Add frontmatter 64 | mdx = "---\n" 65 | for key, value in front_matter.items(): 66 | if isinstance(value, list): 67 | mdx += f"{key}: {', '.join(value)}\n" 68 | else: 69 | mdx += f"{key}: {value}\n" 70 | mdx += "---\n\n" 71 | mdx += f"{self.solutions[0].problem_statement}\n\n" 72 | mdx += "## Solutions\n\n" 73 | for solution in self.solutions: 74 | if len(self.solutions) > 1: 75 | mdx += f"### Method {solution.id}\n\n" 76 | mdx += f"```python\nclass Solution:\n{solution.code}```\n\n" 77 | if "description" in solution.docs: 78 | mdx += f"{solution.docs['description']}\n\n" 79 | if "time" in solution.docs and "args" in solution.docs["time"]: 80 | mdx += f"**Time Complexity**: {solution.docs['time']['args'][1]}, {solution.docs['time']['description']} \n" 81 | if "space" in solution.docs and "args" in solution.docs["space"]: 82 | mdx += f"**Space Complexity**: {solution.docs['space']['args'][1]}, {solution.docs['space']['description']} \n" 83 | mdx += "\n" 84 | if output_filename: 85 | with open(output_filename, "w") as f: 86 | f.write(mdx) 87 | else: 88 | return mdx 89 | 90 | def _extract_code( 91 | self, 92 | node: ast.AsyncFunctionDef | ast.FunctionDef, 93 | ) -> str: 94 | if node.lineno is not None and node.end_lineno is not None: 95 | code_lines = node.lineno, node.end_lineno + 1 96 | else: 97 | raise ValueError("Node does not contain any code.") 98 | doc_lines = get_doc_string_lines(node) 99 | with open(self.filename, "r") as f: 100 | data = f.readlines() 101 | lines_to_retain = [] 102 | for idx, line in enumerate(data): 103 | if doc_lines is not None: 104 | if ((idx + 1) in range(*code_lines)) and ( 105 | (idx + 1) not in range(doc_lines[0], doc_lines[1] + 1) 106 | ): 107 | lines_to_retain.append(line) 108 | else: 109 | if (idx + 1) in range(*code_lines): 110 | lines_to_retain.append(line) 111 | 112 | return "".join(lines_to_retain) 113 | 114 | def _extract_front_matter( 115 | self, front_matter_name: str = "front_matter" 116 | ) -> dict[str, str | list[str]]: 117 | """ 118 | Extracts the front matter from the given AST module. 119 | 120 | Args: 121 | front_matter_name (str): The name of the variable containing the front matter. Defaults to "front_matter". 122 | 123 | Returns: 124 | dict[str, str | list[str]]: The extracted front matter as a dictionary. 125 | 126 | Raises: 127 | ValueError: If the front_matter is not a dictionary. 128 | """ 129 | front_matter = {} 130 | 131 | for item in self.module.body: 132 | if isinstance(item, ast.Assign) and any( 133 | isinstance(target, ast.Name) and target.id == front_matter_name 134 | for target in item.targets 135 | ): 136 | if not isinstance(item.value, ast.Dict): 137 | raise ValueError("front_matter must be a dict") 138 | 139 | for key, value in zip(item.value.keys, item.value.values): 140 | if isinstance(value, ast.Constant): 141 | front_matter[key.s] = value.s 142 | elif isinstance(value, ast.List): 143 | front_matter[key.s] = [el.s for el in value.elts] 144 | 145 | return front_matter 146 | 147 | 148 | def get_doc_string_lines( 149 | node: ast.AsyncFunctionDef | ast.FunctionDef, 150 | ) -> tuple[int, int] | None: 151 | """ 152 | Return the code for the given node after removing the docstring or None 153 | if no code can be found. If the node provided does not have docstrings 154 | a TypeError will be raised. 155 | 156 | If *clean* is `True`, all tabs are expanded to spaces and any whitespace 157 | that can be uniformly removed from the second line onwards is removed. 158 | """ 159 | if not isinstance(node, (ast.AsyncFunctionDef, ast.FunctionDef)): 160 | raise TypeError("%r can't have docstrings" % node.__class__.__name__) 161 | if ( 162 | node.body 163 | and isinstance(node.body[0], ast.Expr) 164 | and node.body[0].lineno 165 | and node.body[0].end_lineno 166 | ): 167 | return node.body[0].lineno, node.body[0].end_lineno 168 | return None 169 | 170 | 171 | def parse_method_docstring(docstring: str | None) -> dict: 172 | if docstring is None: 173 | return {} 174 | 175 | docs = GoogleParser( 176 | sections=DEFAULT_SECTIONS 177 | + [ 178 | Section("Time Complexity", "time", SectionType.SINGULAR_OR_MULTIPLE), 179 | Section("Space Complexity", "space", SectionType.SINGULAR_OR_MULTIPLE), 180 | ] 181 | ).parse(docstring) 182 | time_complexity = [item for item in docs.meta if item.args[0] == "time"] 183 | space_complexity = [item for item in docs.meta if item.args[0] == "space"] 184 | return { 185 | "description": f"{docs.short_description}\n\n{docs.long_description}", 186 | "args": [vars(arg) for arg in docs.params], 187 | "returns": vars(docs.returns), 188 | "examples": [vars(example) for example in docs.examples], 189 | "time": vars(time_complexity[0]) if len(time_complexity) > 0 else {}, 190 | "space": vars(space_complexity[0]) if len(space_complexity) > 0 else {}, 191 | } 192 | -------------------------------------------------------------------------------- /src/leetscrape/questions_list.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import requests 3 | 4 | from ._constants import CATEGORIES, TOPIC_TAGS 5 | 6 | 7 | class GetQuestionsList: 8 | """A class to scrape the list of questions, their topic tags, and company tags. 9 | 10 | Args: 11 | limit (int, optional): The maximum number of questions to query for from Leetcode's graphql API. Defaults to 10,000. 12 | """ 13 | 14 | def __init__(self, limit: int = 10_000): 15 | self.limit = limit 16 | 17 | def scrape(self): 18 | """Scrapes LeetCode data including company tags, questions, question topics, 19 | and categories. 20 | """ 21 | self._scrape_companies() 22 | self._scrape_questions_list() 23 | self._extract_question_topics() 24 | self._get_categories_and_topicTags_lists() 25 | self._scrape_question_category() 26 | self._add_category_to_questions_list() 27 | 28 | def to_csv(self, directory: str) -> None: 29 | """A method to export the scraped data into csv files in preparation for 30 | injection into a database. 31 | 32 | Args: 33 | directory (str): The directory path to export the scraped data into. 34 | """ 35 | self.companies.to_csv(directory + "companies.csv", index=False) 36 | self.questions["QID"] = self.questions["QID"].astype(int) 37 | self.questions.to_csv(directory + "questions.csv", index=False) 38 | self.questionTopics.to_csv( 39 | directory + "questionTopics.csv", index=True, index_label="id" 40 | ) 41 | self.categories.to_csv(directory + "categories.csv", index=False) 42 | self.topicTags.to_csv(directory + "topicTags.csv", index=False) 43 | self.questionCategory.to_csv( 44 | directory + "questionCategory.csv", index=True, index_label="id" 45 | ) 46 | 47 | def _scrape_companies(self): 48 | """Scrape the company tags of each question. This always returns an empty 49 | dataframe as this is a paid only feature.""" 50 | print("Scraping companies ... ", end="") 51 | data = { 52 | "query": """query questionCompanyTags { 53 | companyTags { 54 | name 55 | slug 56 | questionCount 57 | } 58 | } 59 | """, 60 | "variables": {}, 61 | } 62 | r = requests.post("https://leetcode.com/graphql", json=data).json() 63 | self.companies = pd.json_normalize(r["data"]["companyTags"]) 64 | print("Done") 65 | 66 | def _scrape_questions_list(self): 67 | """ 68 | Scrapes the list of questions from leetcode.com and store them in the 'questions' dataframe. The columns include the question QID, acceptance rate, difficulty, title, titleSlug, and topic tags. It also has a column indicating whether the question is available only to Leetcode's paying customers. 69 | """ 70 | print("Scraping questions list ... ", end="") 71 | data = { 72 | "query": """query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) { 73 | problemsetQuestionList: questionList( 74 | categorySlug: $categorySlug 75 | limit: $limit 76 | skip: $skip 77 | filters: $filters 78 | ) { 79 | total: totalNum 80 | questions: data { 81 | acceptanceRate: acRate 82 | difficulty 83 | QID: questionFrontendId 84 | paidOnly: isPaidOnly 85 | title 86 | titleSlug 87 | topicTags { 88 | slug 89 | } 90 | } 91 | } 92 | } 93 | """, 94 | "variables": { 95 | "categorySlug": "", 96 | "skip": 0, 97 | "limit": self.limit, 98 | "filters": {}, 99 | }, 100 | } 101 | 102 | r = requests.post("https://leetcode.com/graphql", json=data).json() 103 | self.questions = pd.json_normalize( 104 | r["data"]["problemsetQuestionList"]["questions"] 105 | )[ 106 | [ 107 | "QID", 108 | "title", 109 | "titleSlug", 110 | "difficulty", 111 | "acceptanceRate", 112 | "paidOnly", 113 | "topicTags", 114 | ] 115 | ] 116 | self.questions["topicTags"] = self.questions["topicTags"].apply( 117 | lambda w: [tag["slug"] for tag in w] 118 | ) 119 | print("Done") 120 | 121 | def _extract_question_topics(self): 122 | """Create a table with the edge list of questions and topic tags.""" 123 | print("Extracting question topics ... ", end="") 124 | self.questionTopics = ( 125 | self.questions[["QID", "topicTags"]] 126 | .rename(columns={"topicTags": "tagSlug"}) 127 | .explode("tagSlug", ignore_index=True) 128 | ).dropna() 129 | print("Done") 130 | 131 | def _get_categories_and_topicTags_lists(self): 132 | """Get the categories and topic tags of LeetCode problems and store them in the 133 | 'categories' and 'topicTags' attribute respectively.""" 134 | print("Getting Categories ... ", end="") 135 | # List of problem categories 136 | self.categories = pd.DataFrame.from_records(CATEGORIES) 137 | print("Done") 138 | # List of problem topic tags 139 | print("Scraping Topic Tags ... ", end="") 140 | self.topicTags = pd.DataFrame.from_records(TOPIC_TAGS) 141 | print("Done") 142 | 143 | def _scrape_question_category(self): 144 | """Scrape the category of each question and store it in the 'questionCategory' dataframe.""" 145 | print("Extracting question category ... ", end="") 146 | categories_data = [] 147 | for category in self.categories["slug"].values: 148 | data = { 149 | "query": """query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) { 150 | problemsetQuestionList: questionList( 151 | categorySlug: $categorySlug 152 | limit: $limit 153 | skip: $skip 154 | filters: $filters 155 | ) { 156 | questions: data { 157 | QID: questionFrontendId 158 | } 159 | } 160 | } 161 | """, 162 | "variables": { 163 | "categorySlug": category, 164 | "skip": 0, 165 | "limit": self.limit, 166 | "filters": {}, 167 | }, 168 | } 169 | 170 | r = requests.post("https://leetcode.com/graphql", json=data).json() 171 | categories = pd.json_normalize( 172 | r["data"]["problemsetQuestionList"]["questions"] 173 | ) 174 | categories["categorySlug"] = category 175 | categories_data.append(categories) 176 | self.questionCategory = pd.concat(categories_data, axis=0, ignore_index=True) 177 | print("Done") 178 | 179 | def _add_category_to_questions_list(self): 180 | """Adds the `topicTags` column containing the comma-separated string of 181 | the list of topic tags relevant to the given questions and the `category` 182 | column that includes the category relevant to the given question""" 183 | self.questions["topicTags"] = self.questions["topicTags"].apply( 184 | lambda w: ",".join(w) 185 | ) 186 | self.questions = self.questions.join( 187 | self.questionCategory.set_index("QID"), on="QID" 188 | ) 189 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeetScrape 2 | 3 | [![deploy-docs](https://github.com/nikhil-ravi/LeetScrape/actions/workflows/pytest-and-docs.yml/badge.svg)](https://leetscrape.nikhilravi.com) [![PYPI](https://img.shields.io/pypi/v/leetscrape)](https://pypi.org/project/leetscrape/) [![codecov](https://codecov.io/gh/nikhil-ravi/LeetScrape/branch/main/graph/badge.svg?token=GWOVLPYSUA)](https://codecov.io/gh/nikhil-ravi/LeetScrape)![PyPI - Downloads](https://img.shields.io/pypi/dm/leetscrape) 4 | 5 | Introducing the LeetScrape - a powerful and efficient Python package designed to scrape problem statements and basic test cases from LeetCode.com. With this package, you can easily download and save LeetCode problems to your local machine, making it convenient for offline practice and studying. It is perfect for software engineers and students preparing for coding interviews. The package is lightweight, easy to use and can be integrated with other tools and IDEs. With the LeetScrape, you can boost your coding skills and improve your chances of landing your dream job. 6 | 7 | Use this package to get the list of Leetcode questions, their topic and company tags, difficulty, question body (including test cases, constraints, hints), and code stubs in any of the available programming languages. 8 | 9 | Detailed documentation available [here](https://leetscrape.nikhilravi.com/). 10 | 11 | There is also a related Next.js web app to serve the scraped questions and your answers at [leetcode-nextjs](https://github.com/nikhil-ravi/leetscrape-ts). See the [demo](https://scuffedcode.nikhilravi.com/). 12 | 13 | ## Get Started 14 | 15 | ### Installation 16 | 17 | Start by installing the package from pip or conda: 18 | 19 | ```bash 20 | # Using pip 21 | pip install leetscrape 22 | 23 | # Using conda: 24 | conda install leetscrape 25 | 26 | # Using poetry: 27 | poetry add leetscrape 28 | ``` 29 | 30 | ### Usage 31 | 32 | #### Command Line 33 | 34 | * leetscrape list [--out OUT] - List all questions without generating code stub. 35 | 36 | ``` 37 | options: 38 | -h, --help show a help message and exit 39 | --out OUT, -o OUT Specify the output file name to store the list of questions. 40 | ``` 41 | * leetscrape question [--out OUT] qid [qid ...] - Generate a code stub for the given question(s). 42 | 43 | ``` 44 | positional arguments: 45 | qid Enter Leetcode question ID(s) 46 | 47 | options: 48 | -h, --help show this help message and exit 49 | --out OUT, -o OUT Enter the path to the output directory 50 | ``` 51 | * leetscrape solution [-h] [--out OUT] input - Generate mdx files from solutions. 52 | 53 | ``` 54 | positional arguments: 55 | input Enter the path to the solution directory with solution files or to a single 56 | solution file 57 | 58 | options: 59 | -h, --help show this help message and exit 60 | --out OUT, -o OUT Enter the path to the output directory to save solutions mdx files 61 | ``` 62 | * leetscrape ts [--out OUT] - Create the leetscrape-ts Next.js project to host the solutions. 63 | 64 | ``` 65 | options: 66 | -h, --help show this help message and exit 67 | --out OUT, -o OUT Enter the path to the output directory to save the project 68 | ``` 69 | 70 | #### Python API 71 | 72 | ##### Get the list of problems and their information 73 | 74 | ```python 75 | from leetscrape import GetQuestionsList 76 | 77 | ls = GetQuestionsList() 78 | ls.scrape() # Scrape the list of questions 79 | ls.questions.head() # Get the list of questions 80 | ``` 81 | 82 | | | QID | title | titleSlug | difficulty | acceptanceRate | paidOnly | topicTags | categorySlug | 83 | |---:|------:|:-----------------------------------------------|:-----------------------------------------------|:-------------|-----------------:|:-----------|:---------------------------------------|:---------------| 84 | | 0 | 1 | Two Sum | two-sum | Easy | 51.4225 | False | array,hash-table | algorithms | 85 | | 1 | 2 | Add Two Numbers | add-two-numbers | Medium | 41.9051 | False | linked-list,math,recursion | algorithms | 86 | | 2 | 3 | Longest Substring Without Repeating Characters | longest-substring-without-repeating-characters | Medium | 34.3169 | False | hash-table,string,sliding-window | algorithms | 87 | | 3 | 4 | Median of Two Sorted Arrays | median-of-two-sorted-arrays | Hard | 38.8566 | False | array,binary-search,divide-and-conquer | algorithms | 88 | | 4 | 5 | Longest Palindromic Substring | longest-palindromic-substring | Medium | 33.4383 | False | string,dynamic-programming | algorithms | 89 | 90 | You can export the associated tables to a directory using the `to_csv` method: 91 | 92 | ```python 93 | ls.to_csv(directory="") 94 | ``` 95 | This generates 6 `.csv` files in the current directory: 96 | - `questions.csv` - List of questions with their title, difficulty, acceptance rate, paid status, topic tags, and category. 97 | - `companies.csv` - List of companies with their name, slug, and the questions count. 98 | - `topicsTags.csv` - List of topic tags with their name and slug. 99 | - `categories.csv` - List of categories with their name and slug. 100 | - `questionCategory.csv` - An edgelist of questions and their categories. 101 | - `questionTopics.csv` - An edgelist of questions and their topic tags. 102 | 103 | ##### Get Question statement and other information 104 | 105 | Query individual question's information such as the body, test cases, constraints, hints, code stubs, and company tags using the `GetQuestion` class: 106 | 107 | ```python 108 | from leetscrape import GetQuestion 109 | 110 | # Get the question body 111 | question = GetQuestion(titleSlug="two-sum").scrape() 112 | ``` 113 | 114 | This returns a `Question` object with the following attributes: 115 | 116 | ```python 117 | question.QID # Question ID 118 | question.title # Question title 119 | question.titleSlug # Question title slug 120 | question.difficulty # Question difficulty 121 | question.Hints # Question hints 122 | question.Companies # Question companies 123 | question.topics # Question topic tags 124 | question.SimilarQuestions # Similar questions ids 125 | question.Code # Code stubs 126 | question.Body # Question body / problem statement 127 | question.isPaidOnly # Whether the question is only available to premium users of Leetcode 128 | ``` 129 | 130 | ##### Generate code stubs for a question 131 | 132 | ```python 133 | from leetscrape import GenerateCodeStub 134 | 135 | # Get the question body 136 | fcs = GenerateCodeStub(titleSlug="two-sum") 137 | fcs.generate(directory="") 138 | ``` 139 | This generates the following files in the given directory: 140 | - `q_0001_twoSum.py` - Python file with the code stub for the given question with a function named `twoSum`. 141 | - `test_q_0001_twoSum.py` - Python file with the test cases for the given question. 142 | 143 | See [examples](./example/solutions/) for examples of the generated code stubs. 144 | 145 | ##### Generate mdx files from solutions 146 | 147 | Once you have solved a question, you can generate an mdx file with the solution and the question statement using the `ExtractSolutions` class: 148 | 149 | ```python 150 | from leetscrape import ExtractSolutions 151 | 152 | # Get the question body 153 | solutions = ExtractSolutions(filename="").extract() 154 | ``` 155 | This outputs a list of `Solution` objects with the following attributes: 156 | 157 | ```python 158 | solution.id # Solution ID 159 | solution.code # Solution code 160 | solution.docs # Docstrings associated with the solution 161 | solution.problem_statement # Question body / problem statement 162 | ``` 163 | 164 | Alternatively, you can use the `to_mdx` method to generate the mdx file: 165 | 166 | ```python 167 | from leetscrape import ExtractSolutions 168 | 169 | # Get the question body 170 | ExtractSolutions(filename="").to_mdx(output_filename="") 171 | ``` 172 | 173 | ### Serving the solutions with [leetscrape-ts](https://github.com/nikhil-ravi/leetscrape-ts) 174 | 175 | You can use the [leetscrape-ts](https://github.com/nikhil-ravi/leetscrape-ts) Next.js template to serve the solutions. See the [demo](https://scuffedcode.nikhilravi.com/). Visit the repo for more details. You can generate the project using the `leetscrape ts` command: 176 | 177 | ```bash 178 | leetscrape ts --out 179 | ``` 180 | This will bootstrap the project in the given directory. Follow the instructions in the [README](https://github.com/nikhil-ravi/leetscrape-ts/blob/main/README.md) and create/modify the `.env.local` file. Then, run the following command to generate the mdx files: 181 | 182 | ```bash 183 | leetscrape solution --out /src/content/solutions 184 | ``` 185 | 186 | You can then run the project using the following command: 187 | 188 | ```bash 189 | cd 190 | npm run dev 191 | # or 192 | yarn dev 193 | # or 194 | pnpm dev 195 | # or 196 | bun dev 197 | ``` 198 | 199 | ## Changelog 200 | 201 | View the changelog [here](https://leetscrape.nikhilravi.com/CHANGELOG/). -------------------------------------------------------------------------------- /src/leetscrape/generate_code_stub.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import marko 4 | from black import FileMode, format_str 5 | from markdownify import markdownify as md 6 | 7 | from ._helper import camel_case, parse_args 8 | from .models import Question 9 | from .question import GetQuestion 10 | 11 | 12 | class GenerateCodeStub: 13 | """Class to generate the code stub and pytest test file for a Leetcode question. The class may be instantiated by either a question's QID or its titleSlug. It creates a code stub with the question's statement, constrainsts, and basic test cases in the docstring. 14 | 15 | It also creates a pytest test file from the basic test cases in the question body. 16 | 17 | Args: 18 | titleSlug (str, optional): The title slug of the question. 19 | qid (int, optional): The frontend question ID of the question. 20 | """ 21 | 22 | def __init__( 23 | self, 24 | titleSlug: str | None = None, 25 | qid: int | None = None, 26 | ): 27 | self.all_questions_stub_id = ( 28 | GetQuestion.fetch_all_questions_id_and_stub().reset_index().set_index("QID") 29 | ) 30 | self.titleSlug = titleSlug 31 | self.qid = qid 32 | if self.titleSlug is None: 33 | if self.qid is None: 34 | raise ValueError( 35 | "At least one of titleSlug or qid needs to be specified." 36 | ) 37 | elif self.qid in self.all_questions_stub_id.index: 38 | self.titleSlug = self.all_questions_stub_id.loc[self.qid].titleSlug 39 | else: 40 | raise ValueError("There is no question with the passed qid") 41 | else: 42 | if self.titleSlug in self.all_questions_stub_id.titleSlug.tolist(): 43 | if self.qid is not None: 44 | if ( 45 | self.titleSlug 46 | != self.all_questions_stub_id.loc[self.qid].titleSlug 47 | ): 48 | raise ValueError( 49 | f"Both titleSlug and qid were passed but they do not match.\n" 50 | + f"{self.qid}: {self.all_questions_stub_id.loc[self.qid].titleSlug}" 51 | ) 52 | else: 53 | self.qid = self.all_questions_stub_id[ 54 | self.all_questions_stub_id["titleSlug"] == self.titleSlug 55 | ].index[0] 56 | else: 57 | raise ValueError("There is no question with the passed titleSlug.") 58 | print(f"Generating code stub for {self.qid}. {self.titleSlug}") 59 | self.filename = f"q_{str(self.qid).zfill(4)}_{camel_case(self.titleSlug)}.py" 60 | questionInfoScraper = GetQuestion(titleSlug=self.titleSlug) 61 | self.data: Question = questionInfoScraper.scrape() 62 | 63 | def generate(self, testing=False, directory: str = ".") -> None: 64 | """Wrapper that creates the code stub and test files after formatting them through black. 65 | 66 | Args: 67 | testing (bool, optional): Whether we are in a testing environment. In testing environment, the files are not written to the disk. Defaults to False. 68 | directory (str, optional): The directory where the files are to be written. Defaults to ".". 69 | """ 70 | if directory.endswith("/"): 71 | directory = directory[:-1] 72 | code_to_write = self._create_code_file() 73 | if not self.data.isPaidOnly: 74 | test_to_write = self._create_test_file(code_to_write) 75 | if not testing: 76 | with open(f"{directory}/{self.filename}", "w", encoding="utf-8") as f: 77 | f.write(format_str(code_to_write, mode=FileMode())) 78 | print(f"Code stub save to {self.filename}") 79 | 80 | if not self.data.isPaidOnly: 81 | with open( 82 | f"{directory}/test_{self.filename}", "w", encoding="utf-8" 83 | ) as f: 84 | f.write( 85 | format_str(test_to_write, mode=FileMode()) 86 | ) # ignore: unbounded 87 | print(f"Test file written to test_{self.filename}.py") 88 | 89 | def _get_code_stub(self) -> str: 90 | """Extracts the python code text from Leetcode's API response. 91 | 92 | Returns: 93 | str: The python code stub. 94 | """ 95 | return self.data.Code 96 | 97 | def _get_problem_statement(self) -> str: 98 | """Extracts the python problem statement from Leetcode's API response. 99 | 100 | Returns: 101 | str: Te problem statement in markdown format. 102 | """ 103 | # Because sup is non-standard markdown, we need to convert them to latex 104 | problem_statement = re.sub(r"(.*?)", r"^{\1}", self.data.Body) 105 | problem_statement_rst = md(problem_statement) 106 | return ( 107 | problem_statement_rst.replace("**Input:**", "Input:") 108 | .replace("**Output:**", "Output:") 109 | .replace("**Explanation:**", "Explanation:") 110 | ) 111 | 112 | def _create_code_file(self) -> str: 113 | """Prepares the text to be written in the python file. 114 | 115 | Returns: 116 | str: The text to be written in the python file. 117 | """ 118 | code_stub = self._get_code_stub() 119 | problem_statement = self._get_problem_statement() 120 | lines_to_write = [] 121 | front_matter = { 122 | "qid": self.data.QID, 123 | "title": self.data.title, 124 | "titleSlug": self.data.titleSlug, 125 | "difficulty": self.data.difficulty, 126 | "tags": self.data.topics, 127 | } 128 | lines_to_write.append(f"front_matter = {front_matter}") 129 | lines_to_write.append( 130 | "# ====================== DO NOT EDIT ABOVE THIS LINE ======================" 131 | ) 132 | for line in code_stub.split("\n"): 133 | lines_to_write.append(line) 134 | if line.startswith("class Solution"): 135 | lines_to_write.append(f' """{problem_statement}"""') 136 | elif line.endswith(":") and not line.strip().startswith("#"): 137 | lines_to_write.append(" pass") 138 | lines_to_write.append( 139 | " # If you have multiple solutions, add them all here as methods of the same class." 140 | ) 141 | text_to_write = "\n".join(lines_to_write).replace("\n\n", "\n") 142 | return text_to_write 143 | 144 | def _extract_codeblocks_in_problem_statement( 145 | self, problem_statement: str 146 | ) -> list[str]: 147 | """Extract the code blocks from the given problem statement string. These codeblocks contain the basic test cases provided by Leetcode. 148 | 149 | Args: 150 | problem_statement (str): The problem statement with the code blocks 151 | 152 | Returns: 153 | list[str]: The list of code blocks. The length of list is equal to the number of basic test cases provided by Leetcode. 154 | """ 155 | mk = marko.Markdown() 156 | markdown_text = mk.parse(problem_statement) 157 | code_blocks = [ 158 | child.children[0].children 159 | for child in markdown_text.children 160 | if isinstance(child, marko.block.FencedCode) 161 | ] 162 | return code_blocks 163 | 164 | def _get_parameters(self, code_blocks: list[str]) -> tuple[str, str]: 165 | """Extract the inputs and outputs from each of the code block in the question body. 166 | 167 | Args: 168 | code_blocks (list[str]): The list of code block in the question body. 169 | 170 | Returns: 171 | tuple[str, str]: 172 | - str: The input string to be added to the test file. 173 | - str: The output string to be added to the test file. 174 | """ 175 | parameters = [] 176 | for test in code_blocks: 177 | if "Input" in test: 178 | for line in test.split("\n"): 179 | if line.startswith("Input:"): 180 | inp = line.split("Input:")[1] 181 | parameter_dict = parse_args(inp) # type: ignore 182 | parameter_dict["output"] = re.search( 183 | "Output: (.*)\n", 184 | test.replace("true", "True").replace( 185 | "false", "False" 186 | ), # Leetcode uses true and false for True and False, respectively. 187 | ) 188 | if parameter_dict["output"] is not None: 189 | parameter_dict["output"] = parse_args( 190 | parameter_dict["output"] 191 | .group(0) 192 | .replace("Output: ", "Output= ") 193 | .replace("\n", "") 194 | )["Output"] 195 | parameters.append(parameter_dict) 196 | output_string = ", ".join(list(parameters[0].keys())) 197 | input_string = ", ".join( 198 | f"({test_case})" 199 | for test_case in [ 200 | ", ".join( 201 | [ 202 | "'{}'".format(x) if isinstance(x, str) else str(x) 203 | for x in parameter.values() 204 | ] 205 | ) 206 | for parameter in parameters 207 | ] 208 | ) 209 | return input_string, output_string 210 | 211 | def _create_test_file(self, code_text: str) -> str: 212 | """Generates the test file for the given question. 213 | 214 | Args: 215 | code_text (str): The text that contains the code stub. This is used to get the list of inputs arguments and the name of the method. 216 | 217 | Returns: 218 | str: The text containing the pytest test case. 219 | """ 220 | problem_statement = self._get_problem_statement() 221 | problem_statement_code_blocks = self._extract_codeblocks_in_problem_statement( 222 | problem_statement 223 | ) 224 | input_string, output_string = self._get_parameters( 225 | problem_statement_code_blocks 226 | ) 227 | pytestParameterDecorator = ( 228 | f"""@pytest.mark.parametrize("{output_string}", [{input_string}])""" 229 | ) 230 | className = "Solution" 231 | 232 | # //TODO: This should be used to find the classname instead of hard-coding it to "Solution" 233 | 234 | # # Use the `parse` function to create an AST from the file's contents 235 | # root = ast.parse(code_text) 236 | # # Iterate through the top-level nodes in the AST 237 | # for node in ast.walk(root): 238 | # # Check if the node is a ClassDef node 239 | # if isinstance(node, ast.ClassDef): 240 | # # Check if the class is not commented 241 | # if not node.name.startswith("#"): 242 | # # Print the class name 243 | # print(node.name) # type: ignore 244 | 245 | methodsName = re.findall("\n def (.*):", code_text) 246 | for i, methodName in enumerate(methodsName): 247 | a, b = methodName.split(") -> ") 248 | methodsName[i] = f"{a}, output: {b})" 249 | methods = [ 250 | f""" 251 | def test_{methodName}: 252 | sc = {className}() 253 | assert sc.{methodName.split("(")[0]}({output_string[:-7]}) == output 254 | """ 255 | for methodName in methodsName 256 | ] 257 | test_to_write = f"""import pytest 258 | from {self.filename.split(".py")[0]} import Solution 259 | 260 | {pytestParameterDecorator} 261 | class Test{className}:""" + "".join( 262 | methods 263 | ) 264 | 265 | return test_to_write 266 | -------------------------------------------------------------------------------- /example/data/questionCategory.csv: -------------------------------------------------------------------------------- 1 | id,QID,categorySlug 2 | 0,1,algorithms 3 | 1,2,algorithms 4 | 2,3,algorithms 5 | 3,4,algorithms 6 | 4,5,algorithms 7 | 5,6,algorithms 8 | 6,7,algorithms 9 | 7,8,algorithms 10 | 8,9,algorithms 11 | 9,10,algorithms 12 | 10,11,algorithms 13 | 11,12,algorithms 14 | 12,13,algorithms 15 | 13,14,algorithms 16 | 14,15,algorithms 17 | 15,16,algorithms 18 | 16,17,algorithms 19 | 17,18,algorithms 20 | 18,19,algorithms 21 | 19,20,algorithms 22 | 20,21,algorithms 23 | 21,22,algorithms 24 | 22,23,algorithms 25 | 23,24,algorithms 26 | 24,25,algorithms 27 | 25,26,algorithms 28 | 26,27,algorithms 29 | 27,28,algorithms 30 | 28,29,algorithms 31 | 29,30,algorithms 32 | 30,31,algorithms 33 | 31,32,algorithms 34 | 32,33,algorithms 35 | 33,34,algorithms 36 | 34,35,algorithms 37 | 35,36,algorithms 38 | 36,37,algorithms 39 | 37,38,algorithms 40 | 38,39,algorithms 41 | 39,40,algorithms 42 | 40,41,algorithms 43 | 41,42,algorithms 44 | 42,43,algorithms 45 | 43,44,algorithms 46 | 44,45,algorithms 47 | 45,46,algorithms 48 | 46,47,algorithms 49 | 47,48,algorithms 50 | 48,49,algorithms 51 | 49,50,algorithms 52 | 50,51,algorithms 53 | 51,52,algorithms 54 | 52,53,algorithms 55 | 53,54,algorithms 56 | 54,55,algorithms 57 | 55,56,algorithms 58 | 56,57,algorithms 59 | 57,58,algorithms 60 | 58,59,algorithms 61 | 59,60,algorithms 62 | 60,61,algorithms 63 | 61,62,algorithms 64 | 62,63,algorithms 65 | 63,64,algorithms 66 | 64,65,algorithms 67 | 65,66,algorithms 68 | 66,67,algorithms 69 | 67,68,algorithms 70 | 68,69,algorithms 71 | 69,70,algorithms 72 | 70,71,algorithms 73 | 71,72,algorithms 74 | 72,73,algorithms 75 | 73,74,algorithms 76 | 74,75,algorithms 77 | 75,76,algorithms 78 | 76,77,algorithms 79 | 77,78,algorithms 80 | 78,79,algorithms 81 | 79,80,algorithms 82 | 80,81,algorithms 83 | 81,82,algorithms 84 | 82,83,algorithms 85 | 83,84,algorithms 86 | 84,85,algorithms 87 | 85,86,algorithms 88 | 86,87,algorithms 89 | 87,88,algorithms 90 | 88,89,algorithms 91 | 89,90,algorithms 92 | 90,91,algorithms 93 | 91,92,algorithms 94 | 92,93,algorithms 95 | 93,94,algorithms 96 | 94,95,algorithms 97 | 95,96,algorithms 98 | 96,97,algorithms 99 | 97,98,algorithms 100 | 98,99,algorithms 101 | 99,100,algorithms 102 | 100,101,algorithms 103 | 101,102,algorithms 104 | 102,103,algorithms 105 | 103,104,algorithms 106 | 104,105,algorithms 107 | 105,106,algorithms 108 | 106,107,algorithms 109 | 107,108,algorithms 110 | 108,109,algorithms 111 | 109,110,algorithms 112 | 110,111,algorithms 113 | 111,112,algorithms 114 | 112,113,algorithms 115 | 113,114,algorithms 116 | 114,115,algorithms 117 | 115,116,algorithms 118 | 116,117,algorithms 119 | 117,118,algorithms 120 | 118,119,algorithms 121 | 119,120,algorithms 122 | 120,121,algorithms 123 | 121,122,algorithms 124 | 122,123,algorithms 125 | 123,124,algorithms 126 | 124,125,algorithms 127 | 125,126,algorithms 128 | 126,127,algorithms 129 | 127,128,algorithms 130 | 128,129,algorithms 131 | 129,130,algorithms 132 | 130,131,algorithms 133 | 131,132,algorithms 134 | 132,133,algorithms 135 | 133,134,algorithms 136 | 134,135,algorithms 137 | 135,136,algorithms 138 | 136,137,algorithms 139 | 137,138,algorithms 140 | 138,139,algorithms 141 | 139,140,algorithms 142 | 140,141,algorithms 143 | 141,142,algorithms 144 | 142,143,algorithms 145 | 143,144,algorithms 146 | 144,145,algorithms 147 | 145,146,algorithms 148 | 146,147,algorithms 149 | 147,148,algorithms 150 | 148,149,algorithms 151 | 149,150,algorithms 152 | 150,151,algorithms 153 | 151,152,algorithms 154 | 152,153,algorithms 155 | 153,154,algorithms 156 | 154,155,algorithms 157 | 155,156,algorithms 158 | 156,157,algorithms 159 | 157,158,algorithms 160 | 158,159,algorithms 161 | 159,160,algorithms 162 | 160,161,algorithms 163 | 161,162,algorithms 164 | 162,163,algorithms 165 | 163,164,algorithms 166 | 164,165,algorithms 167 | 165,166,algorithms 168 | 166,167,algorithms 169 | 167,168,algorithms 170 | 168,169,algorithms 171 | 169,170,algorithms 172 | 170,171,algorithms 173 | 171,172,algorithms 174 | 172,173,algorithms 175 | 173,174,algorithms 176 | 174,179,algorithms 177 | 175,186,algorithms 178 | 176,187,algorithms 179 | 177,188,algorithms 180 | 178,189,algorithms 181 | 179,190,algorithms 182 | 180,191,algorithms 183 | 181,198,algorithms 184 | 182,199,algorithms 185 | 183,200,algorithms 186 | 184,201,algorithms 187 | 185,202,algorithms 188 | 186,203,algorithms 189 | 187,204,algorithms 190 | 188,205,algorithms 191 | 189,206,algorithms 192 | 190,207,algorithms 193 | 191,208,algorithms 194 | 192,209,algorithms 195 | 193,210,algorithms 196 | 194,211,algorithms 197 | 195,212,algorithms 198 | 196,213,algorithms 199 | 197,214,algorithms 200 | 198,215,algorithms 201 | 199,216,algorithms 202 | 200,217,algorithms 203 | 201,218,algorithms 204 | 202,219,algorithms 205 | 203,220,algorithms 206 | 204,221,algorithms 207 | 205,222,algorithms 208 | 206,223,algorithms 209 | 207,224,algorithms 210 | 208,225,algorithms 211 | 209,226,algorithms 212 | 210,227,algorithms 213 | 211,228,algorithms 214 | 212,229,algorithms 215 | 213,230,algorithms 216 | 214,231,algorithms 217 | 215,232,algorithms 218 | 216,233,algorithms 219 | 217,234,algorithms 220 | 218,235,algorithms 221 | 219,236,algorithms 222 | 220,237,algorithms 223 | 221,238,algorithms 224 | 222,239,algorithms 225 | 223,240,algorithms 226 | 224,241,algorithms 227 | 225,242,algorithms 228 | 226,243,algorithms 229 | 227,244,algorithms 230 | 228,245,algorithms 231 | 229,246,algorithms 232 | 230,247,algorithms 233 | 231,248,algorithms 234 | 232,249,algorithms 235 | 233,250,algorithms 236 | 234,251,algorithms 237 | 235,252,algorithms 238 | 236,253,algorithms 239 | 237,254,algorithms 240 | 238,255,algorithms 241 | 239,256,algorithms 242 | 240,257,algorithms 243 | 241,258,algorithms 244 | 242,259,algorithms 245 | 243,260,algorithms 246 | 244,261,algorithms 247 | 245,263,algorithms 248 | 246,264,algorithms 249 | 247,265,algorithms 250 | 248,266,algorithms 251 | 249,267,algorithms 252 | 250,268,algorithms 253 | 251,269,algorithms 254 | 252,270,algorithms 255 | 253,271,algorithms 256 | 254,272,algorithms 257 | 255,273,algorithms 258 | 256,274,algorithms 259 | 257,275,algorithms 260 | 258,276,algorithms 261 | 259,277,algorithms 262 | 260,278,algorithms 263 | 261,279,algorithms 264 | 262,280,algorithms 265 | 263,281,algorithms 266 | 264,282,algorithms 267 | 265,283,algorithms 268 | 266,284,algorithms 269 | 267,285,algorithms 270 | 268,286,algorithms 271 | 269,287,algorithms 272 | 270,288,algorithms 273 | 271,289,algorithms 274 | 272,290,algorithms 275 | 273,291,algorithms 276 | 274,292,algorithms 277 | 275,293,algorithms 278 | 276,294,algorithms 279 | 277,295,algorithms 280 | 278,296,algorithms 281 | 279,297,algorithms 282 | 280,298,algorithms 283 | 281,299,algorithms 284 | 282,300,algorithms 285 | 283,301,algorithms 286 | 284,302,algorithms 287 | 285,303,algorithms 288 | 286,304,algorithms 289 | 287,305,algorithms 290 | 288,306,algorithms 291 | 289,307,algorithms 292 | 290,308,algorithms 293 | 291,309,algorithms 294 | 292,310,algorithms 295 | 293,311,algorithms 296 | 294,312,algorithms 297 | 295,313,algorithms 298 | 296,314,algorithms 299 | 297,315,algorithms 300 | 298,316,algorithms 301 | 299,317,algorithms 302 | 300,318,algorithms 303 | 301,319,algorithms 304 | 302,320,algorithms 305 | 303,321,algorithms 306 | 304,322,algorithms 307 | 305,323,algorithms 308 | 306,324,algorithms 309 | 307,325,algorithms 310 | 308,326,algorithms 311 | 309,327,algorithms 312 | 310,328,algorithms 313 | 311,329,algorithms 314 | 312,330,algorithms 315 | 313,331,algorithms 316 | 314,332,algorithms 317 | 315,333,algorithms 318 | 316,334,algorithms 319 | 317,335,algorithms 320 | 318,336,algorithms 321 | 319,337,algorithms 322 | 320,338,algorithms 323 | 321,339,algorithms 324 | 322,340,algorithms 325 | 323,341,algorithms 326 | 324,342,algorithms 327 | 325,343,algorithms 328 | 326,344,algorithms 329 | 327,345,algorithms 330 | 328,346,algorithms 331 | 329,347,algorithms 332 | 330,348,algorithms 333 | 331,349,algorithms 334 | 332,350,algorithms 335 | 333,351,algorithms 336 | 334,352,algorithms 337 | 335,353,algorithms 338 | 336,354,algorithms 339 | 337,355,algorithms 340 | 338,356,algorithms 341 | 339,357,algorithms 342 | 340,358,algorithms 343 | 341,359,algorithms 344 | 342,360,algorithms 345 | 343,361,algorithms 346 | 344,362,algorithms 347 | 345,363,algorithms 348 | 346,364,algorithms 349 | 347,365,algorithms 350 | 348,366,algorithms 351 | 349,367,algorithms 352 | 350,368,algorithms 353 | 351,369,algorithms 354 | 352,370,algorithms 355 | 353,371,algorithms 356 | 354,372,algorithms 357 | 355,373,algorithms 358 | 356,374,algorithms 359 | 357,375,algorithms 360 | 358,376,algorithms 361 | 359,377,algorithms 362 | 360,378,algorithms 363 | 361,379,algorithms 364 | 362,380,algorithms 365 | 363,381,algorithms 366 | 364,382,algorithms 367 | 365,383,algorithms 368 | 366,384,algorithms 369 | 367,385,algorithms 370 | 368,386,algorithms 371 | 369,387,algorithms 372 | 370,388,algorithms 373 | 371,389,algorithms 374 | 372,390,algorithms 375 | 373,391,algorithms 376 | 374,392,algorithms 377 | 375,393,algorithms 378 | 376,394,algorithms 379 | 377,395,algorithms 380 | 378,396,algorithms 381 | 379,397,algorithms 382 | 380,398,algorithms 383 | 381,399,algorithms 384 | 382,400,algorithms 385 | 383,401,algorithms 386 | 384,402,algorithms 387 | 385,403,algorithms 388 | 386,404,algorithms 389 | 387,405,algorithms 390 | 388,406,algorithms 391 | 389,407,algorithms 392 | 390,408,algorithms 393 | 391,409,algorithms 394 | 392,410,algorithms 395 | 393,411,algorithms 396 | 394,412,algorithms 397 | 395,413,algorithms 398 | 396,414,algorithms 399 | 397,415,algorithms 400 | 398,416,algorithms 401 | 399,417,algorithms 402 | 400,418,algorithms 403 | 401,419,algorithms 404 | 402,420,algorithms 405 | 403,421,algorithms 406 | 404,422,algorithms 407 | 405,423,algorithms 408 | 406,424,algorithms 409 | 407,425,algorithms 410 | 408,426,algorithms 411 | 409,427,algorithms 412 | 410,428,algorithms 413 | 411,429,algorithms 414 | 412,430,algorithms 415 | 413,431,algorithms 416 | 414,432,algorithms 417 | 415,433,algorithms 418 | 416,434,algorithms 419 | 417,435,algorithms 420 | 418,436,algorithms 421 | 419,437,algorithms 422 | 420,438,algorithms 423 | 421,439,algorithms 424 | 422,440,algorithms 425 | 423,441,algorithms 426 | 424,442,algorithms 427 | 425,443,algorithms 428 | 426,444,algorithms 429 | 427,445,algorithms 430 | 428,446,algorithms 431 | 429,447,algorithms 432 | 430,448,algorithms 433 | 431,449,algorithms 434 | 432,450,algorithms 435 | 433,451,algorithms 436 | 434,452,algorithms 437 | 435,453,algorithms 438 | 436,454,algorithms 439 | 437,455,algorithms 440 | 438,456,algorithms 441 | 439,457,algorithms 442 | 440,458,algorithms 443 | 441,459,algorithms 444 | 442,460,algorithms 445 | 443,461,algorithms 446 | 444,462,algorithms 447 | 445,463,algorithms 448 | 446,464,algorithms 449 | 447,465,algorithms 450 | 448,466,algorithms 451 | 449,467,algorithms 452 | 450,468,algorithms 453 | 451,469,algorithms 454 | 452,470,algorithms 455 | 453,471,algorithms 456 | 454,472,algorithms 457 | 455,473,algorithms 458 | 456,474,algorithms 459 | 457,475,algorithms 460 | 458,476,algorithms 461 | 459,477,algorithms 462 | 460,478,algorithms 463 | 461,479,algorithms 464 | 462,480,algorithms 465 | 463,481,algorithms 466 | 464,482,algorithms 467 | 465,483,algorithms 468 | 466,484,algorithms 469 | 467,485,algorithms 470 | 468,486,algorithms 471 | 469,487,algorithms 472 | 470,488,algorithms 473 | 471,489,algorithms 474 | 472,490,algorithms 475 | 473,491,algorithms 476 | 474,492,algorithms 477 | 475,493,algorithms 478 | 476,494,algorithms 479 | 477,495,algorithms 480 | 478,496,algorithms 481 | 479,497,algorithms 482 | 480,498,algorithms 483 | 481,499,algorithms 484 | 482,500,algorithms 485 | 483,501,algorithms 486 | 484,502,algorithms 487 | 485,503,algorithms 488 | 486,504,algorithms 489 | 487,505,algorithms 490 | 488,506,algorithms 491 | 489,507,algorithms 492 | 490,508,algorithms 493 | 491,509,algorithms 494 | 492,510,algorithms 495 | 493,513,algorithms 496 | 494,514,algorithms 497 | 495,515,algorithms 498 | 496,516,algorithms 499 | 497,517,algorithms 500 | 498,518,algorithms 501 | 499,519,algorithms 502 | 500,520,algorithms 503 | 501,521,algorithms 504 | 502,522,algorithms 505 | 503,523,algorithms 506 | 504,524,algorithms 507 | 505,525,algorithms 508 | 506,526,algorithms 509 | 507,527,algorithms 510 | 508,528,algorithms 511 | 509,529,algorithms 512 | 510,530,algorithms 513 | 511,531,algorithms 514 | 512,532,algorithms 515 | 513,533,algorithms 516 | 514,535,algorithms 517 | 515,536,algorithms 518 | 516,537,algorithms 519 | 517,538,algorithms 520 | 518,539,algorithms 521 | 519,540,algorithms 522 | 520,541,algorithms 523 | 521,542,algorithms 524 | 522,543,algorithms 525 | 523,544,algorithms 526 | 524,545,algorithms 527 | 525,546,algorithms 528 | 526,547,algorithms 529 | 527,548,algorithms 530 | 528,549,algorithms 531 | 529,551,algorithms 532 | 530,552,algorithms 533 | 531,553,algorithms 534 | 532,554,algorithms 535 | 533,555,algorithms 536 | 534,556,algorithms 537 | 535,557,algorithms 538 | 536,558,algorithms 539 | 537,559,algorithms 540 | 538,560,algorithms 541 | 539,561,algorithms 542 | 540,562,algorithms 543 | 541,563,algorithms 544 | 542,564,algorithms 545 | 543,565,algorithms 546 | 544,566,algorithms 547 | 545,567,algorithms 548 | 546,568,algorithms 549 | 547,572,algorithms 550 | 548,573,algorithms 551 | 549,575,algorithms 552 | 550,576,algorithms 553 | 551,581,algorithms 554 | 552,582,algorithms 555 | 553,583,algorithms 556 | 554,587,algorithms 557 | 555,588,algorithms 558 | 556,589,algorithms 559 | 557,590,algorithms 560 | 558,591,algorithms 561 | 559,592,algorithms 562 | 560,593,algorithms 563 | 561,594,algorithms 564 | 562,598,algorithms 565 | 563,599,algorithms 566 | 564,600,algorithms 567 | 565,604,algorithms 568 | 566,605,algorithms 569 | 567,606,algorithms 570 | 568,609,algorithms 571 | 569,611,algorithms 572 | 570,616,algorithms 573 | 571,617,algorithms 574 | 572,621,algorithms 575 | 573,622,algorithms 576 | 574,623,algorithms 577 | 575,624,algorithms 578 | 576,625,algorithms 579 | 577,628,algorithms 580 | 578,629,algorithms 581 | 579,630,algorithms 582 | 580,631,algorithms 583 | 581,632,algorithms 584 | 582,633,algorithms 585 | 583,634,algorithms 586 | 584,635,algorithms 587 | 585,636,algorithms 588 | 586,637,algorithms 589 | 587,638,algorithms 590 | 588,639,algorithms 591 | 589,640,algorithms 592 | 590,641,algorithms 593 | 591,642,algorithms 594 | 592,643,algorithms 595 | 593,644,algorithms 596 | 594,645,algorithms 597 | 595,646,algorithms 598 | 596,647,algorithms 599 | 597,648,algorithms 600 | 598,649,algorithms 601 | 599,650,algorithms 602 | 600,651,algorithms 603 | 601,652,algorithms 604 | 602,653,algorithms 605 | 603,654,algorithms 606 | 604,655,algorithms 607 | 605,656,algorithms 608 | 606,657,algorithms 609 | 607,658,algorithms 610 | 608,659,algorithms 611 | 609,660,algorithms 612 | 610,661,algorithms 613 | 611,662,algorithms 614 | 612,663,algorithms 615 | 613,664,algorithms 616 | 614,665,algorithms 617 | 615,666,algorithms 618 | 616,667,algorithms 619 | 617,668,algorithms 620 | 618,669,algorithms 621 | 619,670,algorithms 622 | 620,671,algorithms 623 | 621,672,algorithms 624 | 622,673,algorithms 625 | 623,674,algorithms 626 | 624,675,algorithms 627 | 625,676,algorithms 628 | 626,677,algorithms 629 | 627,678,algorithms 630 | 628,679,algorithms 631 | 629,680,algorithms 632 | 630,681,algorithms 633 | 631,682,algorithms 634 | 632,683,algorithms 635 | 633,684,algorithms 636 | 634,685,algorithms 637 | 635,686,algorithms 638 | 636,687,algorithms 639 | 637,688,algorithms 640 | 638,689,algorithms 641 | 639,690,algorithms 642 | 640,691,algorithms 643 | 641,692,algorithms 644 | 642,693,algorithms 645 | 643,694,algorithms 646 | 644,695,algorithms 647 | 645,696,algorithms 648 | 646,697,algorithms 649 | 647,698,algorithms 650 | 648,699,algorithms 651 | 649,700,algorithms 652 | 650,701,algorithms 653 | 651,702,algorithms 654 | 652,703,algorithms 655 | 653,704,algorithms 656 | 654,705,algorithms 657 | 655,706,algorithms 658 | 656,707,algorithms 659 | 657,708,algorithms 660 | 658,709,algorithms 661 | 659,710,algorithms 662 | 660,711,algorithms 663 | 661,712,algorithms 664 | 662,713,algorithms 665 | 663,714,algorithms 666 | 664,715,algorithms 667 | 665,716,algorithms 668 | 666,717,algorithms 669 | 667,718,algorithms 670 | 668,719,algorithms 671 | 669,720,algorithms 672 | 670,721,algorithms 673 | 671,722,algorithms 674 | 672,723,algorithms 675 | 673,724,algorithms 676 | 674,725,algorithms 677 | 675,726,algorithms 678 | 676,727,algorithms 679 | 677,728,algorithms 680 | 678,729,algorithms 681 | 679,730,algorithms 682 | 680,731,algorithms 683 | 681,732,algorithms 684 | 682,733,algorithms 685 | 683,734,algorithms 686 | 684,735,algorithms 687 | 685,736,algorithms 688 | 686,737,algorithms 689 | 687,738,algorithms 690 | 688,739,algorithms 691 | 689,740,algorithms 692 | 690,741,algorithms 693 | 691,742,algorithms 694 | 692,743,algorithms 695 | 693,744,algorithms 696 | 694,745,algorithms 697 | 695,746,algorithms 698 | 696,747,algorithms 699 | 697,748,algorithms 700 | 698,749,algorithms 701 | 699,750,algorithms 702 | 700,751,algorithms 703 | 701,752,algorithms 704 | 702,753,algorithms 705 | 703,754,algorithms 706 | 704,755,algorithms 707 | 705,756,algorithms 708 | 706,757,algorithms 709 | 707,758,algorithms 710 | 708,759,algorithms 711 | 709,760,algorithms 712 | 710,761,algorithms 713 | 711,762,algorithms 714 | 712,763,algorithms 715 | 713,764,algorithms 716 | 714,765,algorithms 717 | 715,766,algorithms 718 | 716,767,algorithms 719 | 717,768,algorithms 720 | 718,769,algorithms 721 | 719,770,algorithms 722 | 720,771,algorithms 723 | 721,772,algorithms 724 | 722,773,algorithms 725 | 723,774,algorithms 726 | 724,775,algorithms 727 | 725,776,algorithms 728 | 726,777,algorithms 729 | 727,778,algorithms 730 | 728,779,algorithms 731 | 729,780,algorithms 732 | 730,781,algorithms 733 | 731,782,algorithms 734 | 732,783,algorithms 735 | 733,784,algorithms 736 | 734,785,algorithms 737 | 735,786,algorithms 738 | 736,787,algorithms 739 | 737,788,algorithms 740 | 738,789,algorithms 741 | 739,790,algorithms 742 | 740,791,algorithms 743 | 741,792,algorithms 744 | 742,793,algorithms 745 | 743,794,algorithms 746 | 744,795,algorithms 747 | 745,796,algorithms 748 | 746,797,algorithms 749 | 747,798,algorithms 750 | 748,799,algorithms 751 | 749,800,algorithms 752 | 750,801,algorithms 753 | 751,802,algorithms 754 | 752,803,algorithms 755 | 753,804,algorithms 756 | 754,805,algorithms 757 | 755,806,algorithms 758 | 756,807,algorithms 759 | 757,808,algorithms 760 | 758,809,algorithms 761 | 759,810,algorithms 762 | 760,811,algorithms 763 | 761,812,algorithms 764 | 762,813,algorithms 765 | 763,814,algorithms 766 | 764,815,algorithms 767 | 765,816,algorithms 768 | 766,817,algorithms 769 | 767,818,algorithms 770 | 768,819,algorithms 771 | 769,820,algorithms 772 | 770,821,algorithms 773 | 771,822,algorithms 774 | 772,823,algorithms 775 | 773,824,algorithms 776 | 774,825,algorithms 777 | 775,826,algorithms 778 | 776,827,algorithms 779 | 777,828,algorithms 780 | 778,829,algorithms 781 | 779,830,algorithms 782 | 780,831,algorithms 783 | 781,832,algorithms 784 | 782,833,algorithms 785 | 783,834,algorithms 786 | 784,835,algorithms 787 | 785,836,algorithms 788 | 786,837,algorithms 789 | 787,838,algorithms 790 | 788,839,algorithms 791 | 789,840,algorithms 792 | 790,841,algorithms 793 | 791,842,algorithms 794 | 792,843,algorithms 795 | 793,844,algorithms 796 | 794,845,algorithms 797 | 795,846,algorithms 798 | 796,847,algorithms 799 | 797,848,algorithms 800 | 798,849,algorithms 801 | 799,850,algorithms 802 | 800,851,algorithms 803 | 801,852,algorithms 804 | 802,853,algorithms 805 | 803,854,algorithms 806 | 804,855,algorithms 807 | 805,856,algorithms 808 | 806,857,algorithms 809 | 807,858,algorithms 810 | 808,859,algorithms 811 | 809,860,algorithms 812 | 810,861,algorithms 813 | 811,862,algorithms 814 | 812,863,algorithms 815 | 813,864,algorithms 816 | 814,865,algorithms 817 | 815,866,algorithms 818 | 816,867,algorithms 819 | 817,868,algorithms 820 | 818,869,algorithms 821 | 819,870,algorithms 822 | 820,871,algorithms 823 | 821,872,algorithms 824 | 822,873,algorithms 825 | 823,874,algorithms 826 | 824,875,algorithms 827 | 825,876,algorithms 828 | 826,877,algorithms 829 | 827,878,algorithms 830 | 828,879,algorithms 831 | 829,880,algorithms 832 | 830,881,algorithms 833 | 831,882,algorithms 834 | 832,883,algorithms 835 | 833,884,algorithms 836 | 834,885,algorithms 837 | 835,886,algorithms 838 | 836,887,algorithms 839 | 837,888,algorithms 840 | 838,889,algorithms 841 | 839,890,algorithms 842 | 840,891,algorithms 843 | 841,892,algorithms 844 | 842,893,algorithms 845 | 843,894,algorithms 846 | 844,895,algorithms 847 | 845,896,algorithms 848 | 846,897,algorithms 849 | 847,898,algorithms 850 | 848,899,algorithms 851 | 849,900,algorithms 852 | 850,901,algorithms 853 | 851,902,algorithms 854 | 852,903,algorithms 855 | 853,904,algorithms 856 | 854,905,algorithms 857 | 855,906,algorithms 858 | 856,907,algorithms 859 | 857,908,algorithms 860 | 858,909,algorithms 861 | 859,910,algorithms 862 | 860,911,algorithms 863 | 861,912,algorithms 864 | 862,913,algorithms 865 | 863,914,algorithms 866 | 864,915,algorithms 867 | 865,916,algorithms 868 | 866,917,algorithms 869 | 867,918,algorithms 870 | 868,919,algorithms 871 | 869,920,algorithms 872 | 870,921,algorithms 873 | 871,922,algorithms 874 | 872,923,algorithms 875 | 873,924,algorithms 876 | 874,925,algorithms 877 | 875,926,algorithms 878 | 876,927,algorithms 879 | 877,928,algorithms 880 | 878,929,algorithms 881 | 879,930,algorithms 882 | 880,931,algorithms 883 | 881,932,algorithms 884 | 882,933,algorithms 885 | 883,934,algorithms 886 | 884,935,algorithms 887 | 885,936,algorithms 888 | 886,937,algorithms 889 | 887,938,algorithms 890 | 888,939,algorithms 891 | 889,940,algorithms 892 | 890,941,algorithms 893 | 891,942,algorithms 894 | 892,943,algorithms 895 | 893,944,algorithms 896 | 894,945,algorithms 897 | 895,946,algorithms 898 | 896,947,algorithms 899 | 897,948,algorithms 900 | 898,949,algorithms 901 | 899,950,algorithms 902 | 900,951,algorithms 903 | 901,952,algorithms 904 | 902,953,algorithms 905 | 903,954,algorithms 906 | 904,955,algorithms 907 | 905,956,algorithms 908 | 906,957,algorithms 909 | 907,958,algorithms 910 | 908,959,algorithms 911 | 909,960,algorithms 912 | 910,961,algorithms 913 | 911,962,algorithms 914 | 912,963,algorithms 915 | 913,964,algorithms 916 | 914,965,algorithms 917 | 915,966,algorithms 918 | 916,967,algorithms 919 | 917,968,algorithms 920 | 918,969,algorithms 921 | 919,970,algorithms 922 | 920,971,algorithms 923 | 921,972,algorithms 924 | 922,973,algorithms 925 | 923,974,algorithms 926 | 924,975,algorithms 927 | 925,976,algorithms 928 | 926,977,algorithms 929 | 927,978,algorithms 930 | 928,979,algorithms 931 | 929,980,algorithms 932 | 930,981,algorithms 933 | 931,982,algorithms 934 | 932,983,algorithms 935 | 933,984,algorithms 936 | 934,985,algorithms 937 | 935,986,algorithms 938 | 936,987,algorithms 939 | 937,988,algorithms 940 | 938,989,algorithms 941 | 939,990,algorithms 942 | 940,991,algorithms 943 | 941,992,algorithms 944 | 942,993,algorithms 945 | 943,994,algorithms 946 | 944,995,algorithms 947 | 945,996,algorithms 948 | 946,997,algorithms 949 | 947,998,algorithms 950 | 948,999,algorithms 951 | 949,1000,algorithms 952 | 950,1001,algorithms 953 | 951,1002,algorithms 954 | 952,1003,algorithms 955 | 953,1004,algorithms 956 | 954,1005,algorithms 957 | 955,1006,algorithms 958 | 956,1007,algorithms 959 | 957,1008,algorithms 960 | 958,1009,algorithms 961 | 959,1010,algorithms 962 | 960,1011,algorithms 963 | 961,1012,algorithms 964 | 962,1013,algorithms 965 | 963,1014,algorithms 966 | 964,1015,algorithms 967 | 965,1016,algorithms 968 | 966,1017,algorithms 969 | 967,1018,algorithms 970 | 968,1019,algorithms 971 | 969,1020,algorithms 972 | 970,1021,algorithms 973 | 971,1022,algorithms 974 | 972,1023,algorithms 975 | 973,1024,algorithms 976 | 974,1025,algorithms 977 | 975,1026,algorithms 978 | 976,1027,algorithms 979 | 977,1028,algorithms 980 | 978,1029,algorithms 981 | 979,1030,algorithms 982 | 980,1031,algorithms 983 | 981,1032,algorithms 984 | 982,1033,algorithms 985 | 983,1034,algorithms 986 | 984,1035,algorithms 987 | 985,1036,algorithms 988 | 986,1037,algorithms 989 | 987,1038,algorithms 990 | 988,1039,algorithms 991 | 989,1040,algorithms 992 | 990,1041,algorithms 993 | 991,1042,algorithms 994 | 992,1043,algorithms 995 | 993,1044,algorithms 996 | 994,1046,algorithms 997 | 995,1047,algorithms 998 | 996,1048,algorithms 999 | 997,1049,algorithms 1000 | 998,1051,algorithms 1001 | 999,1052,algorithms 1002 | 1000,1053,algorithms 1003 | 1001,1054,algorithms 1004 | 1002,1055,algorithms 1005 | 1003,1056,algorithms 1006 | 1004,1057,algorithms 1007 | 1005,1058,algorithms 1008 | 1006,1059,algorithms 1009 | 1007,1060,algorithms 1010 | 1008,1061,algorithms 1011 | 1009,1062,algorithms 1012 | 1010,1063,algorithms 1013 | 1011,1064,algorithms 1014 | 1012,1065,algorithms 1015 | 1013,1066,algorithms 1016 | 1014,1067,algorithms 1017 | 1015,1071,algorithms 1018 | 1016,1072,algorithms 1019 | 1017,1073,algorithms 1020 | 1018,1074,algorithms 1021 | 1019,1078,algorithms 1022 | 1020,1079,algorithms 1023 | 1021,1080,algorithms 1024 | 1022,1081,algorithms 1025 | 1023,1085,algorithms 1026 | 1024,1086,algorithms 1027 | 1025,1087,algorithms 1028 | 1026,1088,algorithms 1029 | 1027,1089,algorithms 1030 | 1028,1090,algorithms 1031 | 1029,1091,algorithms 1032 | 1030,1092,algorithms 1033 | 1031,1093,algorithms 1034 | 1032,1094,algorithms 1035 | 1033,1095,algorithms 1036 | 1034,1096,algorithms 1037 | 1035,1099,algorithms 1038 | 1036,1100,algorithms 1039 | 1037,1101,algorithms 1040 | 1038,1102,algorithms 1041 | 1039,1103,algorithms 1042 | 1040,1104,algorithms 1043 | 1041,1105,algorithms 1044 | 1042,1106,algorithms 1045 | 1043,1108,algorithms 1046 | 1044,1109,algorithms 1047 | 1045,1110,algorithms 1048 | 1046,1111,algorithms 1049 | 1047,1118,algorithms 1050 | 1048,1119,algorithms 1051 | 1049,1120,algorithms 1052 | 1050,1121,algorithms 1053 | 1051,1122,algorithms 1054 | 1052,1123,algorithms 1055 | 1053,1124,algorithms 1056 | 1054,1125,algorithms 1057 | 1055,1128,algorithms 1058 | 1056,1129,algorithms 1059 | 1057,1130,algorithms 1060 | 1058,1131,algorithms 1061 | 1059,1133,algorithms 1062 | 1060,1134,algorithms 1063 | 1061,1135,algorithms 1064 | 1062,1136,algorithms 1065 | 1063,1137,algorithms 1066 | 1064,1138,algorithms 1067 | 1065,1139,algorithms 1068 | 1066,1140,algorithms 1069 | 1067,1143,algorithms 1070 | 1068,1144,algorithms 1071 | 1069,1145,algorithms 1072 | 1070,1146,algorithms 1073 | 1071,1147,algorithms 1074 | 1072,1150,algorithms 1075 | 1073,1151,algorithms 1076 | 1074,1152,algorithms 1077 | 1075,1153,algorithms 1078 | 1076,1154,algorithms 1079 | 1077,1155,algorithms 1080 | 1078,1156,algorithms 1081 | 1079,1157,algorithms 1082 | 1080,1160,algorithms 1083 | 1081,1161,algorithms 1084 | 1082,1162,algorithms 1085 | 1083,1163,algorithms 1086 | 1084,1165,algorithms 1087 | 1085,1166,algorithms 1088 | 1086,1167,algorithms 1089 | 1087,1168,algorithms 1090 | 1088,1169,algorithms 1091 | 1089,1170,algorithms 1092 | 1090,1171,algorithms 1093 | 1091,1172,algorithms 1094 | 1092,1175,algorithms 1095 | 1093,1176,algorithms 1096 | 1094,1177,algorithms 1097 | 1095,1178,algorithms 1098 | 1096,1180,algorithms 1099 | 1097,1181,algorithms 1100 | 1098,1182,algorithms 1101 | 1099,1183,algorithms 1102 | 1100,1184,algorithms 1103 | 1101,1185,algorithms 1104 | 1102,1186,algorithms 1105 | 1103,1187,algorithms 1106 | 1104,1189,algorithms 1107 | 1105,1190,algorithms 1108 | 1106,1191,algorithms 1109 | 1107,1192,algorithms 1110 | 1108,1196,algorithms 1111 | 1109,1197,algorithms 1112 | 1110,1198,algorithms 1113 | 1111,1199,algorithms 1114 | 1112,1200,algorithms 1115 | 1113,1201,algorithms 1116 | 1114,1202,algorithms 1117 | 1115,1203,algorithms 1118 | 1116,1206,algorithms 1119 | 1117,1207,algorithms 1120 | 1118,1208,algorithms 1121 | 1119,1209,algorithms 1122 | 1120,1210,algorithms 1123 | 1121,1213,algorithms 1124 | 1122,1214,algorithms 1125 | 1123,1215,algorithms 1126 | 1124,1216,algorithms 1127 | 1125,1217,algorithms 1128 | 1126,1218,algorithms 1129 | 1127,1219,algorithms 1130 | 1128,1220,algorithms 1131 | 1129,1221,algorithms 1132 | 1130,1222,algorithms 1133 | 1131,1223,algorithms 1134 | 1132,1224,algorithms 1135 | 1133,1227,algorithms 1136 | 1134,1228,algorithms 1137 | 1135,1229,algorithms 1138 | 1136,1230,algorithms 1139 | 1137,1231,algorithms 1140 | 1138,1232,algorithms 1141 | 1139,1233,algorithms 1142 | 1140,1234,algorithms 1143 | 1141,1235,algorithms 1144 | 1142,1236,algorithms 1145 | 1143,1237,algorithms 1146 | 1144,1238,algorithms 1147 | 1145,1239,algorithms 1148 | 1146,1240,algorithms 1149 | 1147,1243,algorithms 1150 | 1148,1244,algorithms 1151 | 1149,1245,algorithms 1152 | 1150,1246,algorithms 1153 | 1151,1247,algorithms 1154 | 1152,1248,algorithms 1155 | 1153,1249,algorithms 1156 | 1154,1250,algorithms 1157 | 1155,1252,algorithms 1158 | 1156,1253,algorithms 1159 | 1157,1254,algorithms 1160 | 1158,1255,algorithms 1161 | 1159,1256,algorithms 1162 | 1160,1257,algorithms 1163 | 1161,1258,algorithms 1164 | 1162,1259,algorithms 1165 | 1163,1260,algorithms 1166 | 1164,1261,algorithms 1167 | 1165,1262,algorithms 1168 | 1166,1263,algorithms 1169 | 1167,1265,algorithms 1170 | 1168,1266,algorithms 1171 | 1169,1267,algorithms 1172 | 1170,1268,algorithms 1173 | 1171,1269,algorithms 1174 | 1172,1271,algorithms 1175 | 1173,1272,algorithms 1176 | 1174,1273,algorithms 1177 | 1175,1274,algorithms 1178 | 1176,1275,algorithms 1179 | 1177,1276,algorithms 1180 | 1178,1277,algorithms 1181 | 1179,1278,algorithms 1182 | 1180,1281,algorithms 1183 | 1181,1282,algorithms 1184 | 1182,1283,algorithms 1185 | 1183,1284,algorithms 1186 | 1184,1286,algorithms 1187 | 1185,1287,algorithms 1188 | 1186,1288,algorithms 1189 | 1187,1289,algorithms 1190 | 1188,1290,algorithms 1191 | 1189,1291,algorithms 1192 | 1190,1292,algorithms 1193 | 1191,1293,algorithms 1194 | 1192,1295,algorithms 1195 | 1193,1296,algorithms 1196 | 1194,1297,algorithms 1197 | 1195,1298,algorithms 1198 | 1196,1299,algorithms 1199 | 1197,1300,algorithms 1200 | 1198,1301,algorithms 1201 | 1199,1302,algorithms 1202 | 1200,1304,algorithms 1203 | 1201,1305,algorithms 1204 | 1202,1306,algorithms 1205 | 1203,1307,algorithms 1206 | 1204,1309,algorithms 1207 | 1205,1310,algorithms 1208 | 1206,1311,algorithms 1209 | 1207,1312,algorithms 1210 | 1208,1313,algorithms 1211 | 1209,1314,algorithms 1212 | 1210,1315,algorithms 1213 | 1211,1316,algorithms 1214 | 1212,1317,algorithms 1215 | 1213,1318,algorithms 1216 | 1214,1319,algorithms 1217 | 1215,1320,algorithms 1218 | 1216,1323,algorithms 1219 | 1217,1324,algorithms 1220 | 1218,1325,algorithms 1221 | 1219,1326,algorithms 1222 | 1220,1328,algorithms 1223 | 1221,1329,algorithms 1224 | 1222,1330,algorithms 1225 | 1223,1331,algorithms 1226 | 1224,1332,algorithms 1227 | 1225,1333,algorithms 1228 | 1226,1334,algorithms 1229 | 1227,1335,algorithms 1230 | 1228,1337,algorithms 1231 | 1229,1338,algorithms 1232 | 1230,1339,algorithms 1233 | 1231,1340,algorithms 1234 | 1232,1342,algorithms 1235 | 1233,1343,algorithms 1236 | 1234,1344,algorithms 1237 | 1235,1345,algorithms 1238 | 1236,1346,algorithms 1239 | 1237,1347,algorithms 1240 | 1238,1348,algorithms 1241 | 1239,1349,algorithms 1242 | 1240,1351,algorithms 1243 | 1241,1352,algorithms 1244 | 1242,1353,algorithms 1245 | 1243,1354,algorithms 1246 | 1244,1356,algorithms 1247 | 1245,1357,algorithms 1248 | 1246,1358,algorithms 1249 | 1247,1359,algorithms 1250 | 1248,1360,algorithms 1251 | 1249,1361,algorithms 1252 | 1250,1362,algorithms 1253 | 1251,1363,algorithms 1254 | 1252,1365,algorithms 1255 | 1253,1366,algorithms 1256 | 1254,1367,algorithms 1257 | 1255,1368,algorithms 1258 | 1256,1370,algorithms 1259 | 1257,1371,algorithms 1260 | 1258,1372,algorithms 1261 | 1259,1373,algorithms 1262 | 1260,1374,algorithms 1263 | 1261,1375,algorithms 1264 | 1262,1376,algorithms 1265 | 1263,1377,algorithms 1266 | 1264,1379,algorithms 1267 | 1265,1380,algorithms 1268 | 1266,1381,algorithms 1269 | 1267,1382,algorithms 1270 | 1268,1383,algorithms 1271 | 1269,1385,algorithms 1272 | 1270,1386,algorithms 1273 | 1271,1387,algorithms 1274 | 1272,1388,algorithms 1275 | 1273,1389,algorithms 1276 | 1274,1390,algorithms 1277 | 1275,1391,algorithms 1278 | 1276,1392,algorithms 1279 | 1277,1394,algorithms 1280 | 1278,1395,algorithms 1281 | 1279,1396,algorithms 1282 | 1280,1397,algorithms 1283 | 1281,1399,algorithms 1284 | 1282,1400,algorithms 1285 | 1283,1401,algorithms 1286 | 1284,1402,algorithms 1287 | 1285,1403,algorithms 1288 | 1286,1404,algorithms 1289 | 1287,1405,algorithms 1290 | 1288,1406,algorithms 1291 | 1289,1408,algorithms 1292 | 1290,1409,algorithms 1293 | 1291,1410,algorithms 1294 | 1292,1411,algorithms 1295 | 1293,1413,algorithms 1296 | 1294,1414,algorithms 1297 | 1295,1415,algorithms 1298 | 1296,1416,algorithms 1299 | 1297,1417,algorithms 1300 | 1298,1418,algorithms 1301 | 1299,1419,algorithms 1302 | 1300,1420,algorithms 1303 | 1301,1422,algorithms 1304 | 1302,1423,algorithms 1305 | 1303,1424,algorithms 1306 | 1304,1425,algorithms 1307 | 1305,1426,algorithms 1308 | 1306,1427,algorithms 1309 | 1307,1428,algorithms 1310 | 1308,1429,algorithms 1311 | 1309,1430,algorithms 1312 | 1310,1431,algorithms 1313 | 1311,1432,algorithms 1314 | 1312,1433,algorithms 1315 | 1313,1434,algorithms 1316 | 1314,1436,algorithms 1317 | 1315,1437,algorithms 1318 | 1316,1438,algorithms 1319 | 1317,1439,algorithms 1320 | 1318,1441,algorithms 1321 | 1319,1442,algorithms 1322 | 1320,1443,algorithms 1323 | 1321,1444,algorithms 1324 | 1322,1446,algorithms 1325 | 1323,1447,algorithms 1326 | 1324,1448,algorithms 1327 | 1325,1449,algorithms 1328 | 1326,1450,algorithms 1329 | 1327,1451,algorithms 1330 | 1328,1452,algorithms 1331 | 1329,1453,algorithms 1332 | 1330,1455,algorithms 1333 | 1331,1456,algorithms 1334 | 1332,1457,algorithms 1335 | 1333,1458,algorithms 1336 | 1334,1460,algorithms 1337 | 1335,1461,algorithms 1338 | 1336,1462,algorithms 1339 | 1337,1463,algorithms 1340 | 1338,1464,algorithms 1341 | 1339,1465,algorithms 1342 | 1340,1466,algorithms 1343 | 1341,1467,algorithms 1344 | 1342,1469,algorithms 1345 | 1343,1470,algorithms 1346 | 1344,1471,algorithms 1347 | 1345,1472,algorithms 1348 | 1346,1473,algorithms 1349 | 1347,1474,algorithms 1350 | 1348,1475,algorithms 1351 | 1349,1476,algorithms 1352 | 1350,1477,algorithms 1353 | 1351,1478,algorithms 1354 | 1352,1480,algorithms 1355 | 1353,1481,algorithms 1356 | 1354,1482,algorithms 1357 | 1355,1483,algorithms 1358 | 1356,1485,algorithms 1359 | 1357,1486,algorithms 1360 | 1358,1487,algorithms 1361 | 1359,1488,algorithms 1362 | 1360,1489,algorithms 1363 | 1361,1490,algorithms 1364 | 1362,1491,algorithms 1365 | 1363,1492,algorithms 1366 | 1364,1493,algorithms 1367 | 1365,1494,algorithms 1368 | 1366,1496,algorithms 1369 | 1367,1497,algorithms 1370 | 1368,1498,algorithms 1371 | 1369,1499,algorithms 1372 | 1370,1500,algorithms 1373 | 1371,1502,algorithms 1374 | 1372,1503,algorithms 1375 | 1373,1504,algorithms 1376 | 1374,1505,algorithms 1377 | 1375,1506,algorithms 1378 | 1376,1507,algorithms 1379 | 1377,1508,algorithms 1380 | 1378,1509,algorithms 1381 | 1379,1510,algorithms 1382 | 1380,1512,algorithms 1383 | 1381,1513,algorithms 1384 | 1382,1514,algorithms 1385 | 1383,1515,algorithms 1386 | 1384,1516,algorithms 1387 | 1385,1518,algorithms 1388 | 1386,1519,algorithms 1389 | 1387,1520,algorithms 1390 | 1388,1521,algorithms 1391 | 1389,1522,algorithms 1392 | 1390,1523,algorithms 1393 | 1391,1524,algorithms 1394 | 1392,1525,algorithms 1395 | 1393,1526,algorithms 1396 | 1394,1528,algorithms 1397 | 1395,1529,algorithms 1398 | 1396,1530,algorithms 1399 | 1397,1531,algorithms 1400 | 1398,1533,algorithms 1401 | 1399,1534,algorithms 1402 | 1400,1535,algorithms 1403 | 1401,1536,algorithms 1404 | 1402,1537,algorithms 1405 | 1403,1538,algorithms 1406 | 1404,1539,algorithms 1407 | 1405,1540,algorithms 1408 | 1406,1541,algorithms 1409 | 1407,1542,algorithms 1410 | 1408,1544,algorithms 1411 | 1409,1545,algorithms 1412 | 1410,1546,algorithms 1413 | 1411,1547,algorithms 1414 | 1412,1548,algorithms 1415 | 1413,1550,algorithms 1416 | 1414,1551,algorithms 1417 | 1415,1552,algorithms 1418 | 1416,1553,algorithms 1419 | 1417,1554,algorithms 1420 | 1418,1556,algorithms 1421 | 1419,1557,algorithms 1422 | 1420,1558,algorithms 1423 | 1421,1559,algorithms 1424 | 1422,1560,algorithms 1425 | 1423,1561,algorithms 1426 | 1424,1562,algorithms 1427 | 1425,1563,algorithms 1428 | 1426,1564,algorithms 1429 | 1427,1566,algorithms 1430 | 1428,1567,algorithms 1431 | 1429,1568,algorithms 1432 | 1430,1569,algorithms 1433 | 1431,1570,algorithms 1434 | 1432,1572,algorithms 1435 | 1433,1573,algorithms 1436 | 1434,1574,algorithms 1437 | 1435,1575,algorithms 1438 | 1436,1576,algorithms 1439 | 1437,1577,algorithms 1440 | 1438,1578,algorithms 1441 | 1439,1579,algorithms 1442 | 1440,1580,algorithms 1443 | 1441,1582,algorithms 1444 | 1442,1583,algorithms 1445 | 1443,1584,algorithms 1446 | 1444,1585,algorithms 1447 | 1445,1586,algorithms 1448 | 1446,1588,algorithms 1449 | 1447,1589,algorithms 1450 | 1448,1590,algorithms 1451 | 1449,1591,algorithms 1452 | 1450,1592,algorithms 1453 | 1451,1593,algorithms 1454 | 1452,1594,algorithms 1455 | 1453,1595,algorithms 1456 | 1454,1597,algorithms 1457 | 1455,1598,algorithms 1458 | 1456,1599,algorithms 1459 | 1457,1600,algorithms 1460 | 1458,1601,algorithms 1461 | 1459,1602,algorithms 1462 | 1460,1603,algorithms 1463 | 1461,1604,algorithms 1464 | 1462,1605,algorithms 1465 | 1463,1606,algorithms 1466 | 1464,1608,algorithms 1467 | 1465,1609,algorithms 1468 | 1466,1610,algorithms 1469 | 1467,1611,algorithms 1470 | 1468,1612,algorithms 1471 | 1469,1614,algorithms 1472 | 1470,1615,algorithms 1473 | 1471,1616,algorithms 1474 | 1472,1617,algorithms 1475 | 1473,1618,algorithms 1476 | 1474,1619,algorithms 1477 | 1475,1620,algorithms 1478 | 1476,1621,algorithms 1479 | 1477,1622,algorithms 1480 | 1478,1624,algorithms 1481 | 1479,1625,algorithms 1482 | 1480,1626,algorithms 1483 | 1481,1627,algorithms 1484 | 1482,1628,algorithms 1485 | 1483,1629,algorithms 1486 | 1484,1630,algorithms 1487 | 1485,1631,algorithms 1488 | 1486,1632,algorithms 1489 | 1487,1634,algorithms 1490 | 1488,1636,algorithms 1491 | 1489,1637,algorithms 1492 | 1490,1638,algorithms 1493 | 1491,1639,algorithms 1494 | 1492,1640,algorithms 1495 | 1493,1641,algorithms 1496 | 1494,1642,algorithms 1497 | 1495,1643,algorithms 1498 | 1496,1644,algorithms 1499 | 1497,1646,algorithms 1500 | 1498,1647,algorithms 1501 | 1499,1648,algorithms 1502 | 1500,1649,algorithms 1503 | 1501,1650,algorithms 1504 | 1502,1652,algorithms 1505 | 1503,1653,algorithms 1506 | 1504,1654,algorithms 1507 | 1505,1655,algorithms 1508 | 1506,1656,algorithms 1509 | 1507,1657,algorithms 1510 | 1508,1658,algorithms 1511 | 1509,1659,algorithms 1512 | 1510,1660,algorithms 1513 | 1511,1662,algorithms 1514 | 1512,1663,algorithms 1515 | 1513,1664,algorithms 1516 | 1514,1665,algorithms 1517 | 1515,1666,algorithms 1518 | 1516,1668,algorithms 1519 | 1517,1669,algorithms 1520 | 1518,1670,algorithms 1521 | 1519,1671,algorithms 1522 | 1520,1672,algorithms 1523 | 1521,1673,algorithms 1524 | 1522,1674,algorithms 1525 | 1523,1675,algorithms 1526 | 1524,1676,algorithms 1527 | 1525,1678,algorithms 1528 | 1526,1679,algorithms 1529 | 1527,1680,algorithms 1530 | 1528,1681,algorithms 1531 | 1529,1682,algorithms 1532 | 1530,1684,algorithms 1533 | 1531,1685,algorithms 1534 | 1532,1686,algorithms 1535 | 1533,1687,algorithms 1536 | 1534,1688,algorithms 1537 | 1535,1689,algorithms 1538 | 1536,1690,algorithms 1539 | 1537,1691,algorithms 1540 | 1538,1692,algorithms 1541 | 1539,1694,algorithms 1542 | 1540,1695,algorithms 1543 | 1541,1696,algorithms 1544 | 1542,1697,algorithms 1545 | 1543,1698,algorithms 1546 | 1544,1700,algorithms 1547 | 1545,1701,algorithms 1548 | 1546,1702,algorithms 1549 | 1547,1703,algorithms 1550 | 1548,1704,algorithms 1551 | 1549,1705,algorithms 1552 | 1550,1706,algorithms 1553 | 1551,1707,algorithms 1554 | 1552,1708,algorithms 1555 | 1553,1710,algorithms 1556 | 1554,1711,algorithms 1557 | 1555,1712,algorithms 1558 | 1556,1713,algorithms 1559 | 1557,1714,algorithms 1560 | 1558,1716,algorithms 1561 | 1559,1717,algorithms 1562 | 1560,1718,algorithms 1563 | 1561,1719,algorithms 1564 | 1562,1720,algorithms 1565 | 1563,1721,algorithms 1566 | 1564,1722,algorithms 1567 | 1565,1723,algorithms 1568 | 1566,1724,algorithms 1569 | 1567,1725,algorithms 1570 | 1568,1726,algorithms 1571 | 1569,1727,algorithms 1572 | 1570,1728,algorithms 1573 | 1571,1730,algorithms 1574 | 1572,1732,algorithms 1575 | 1573,1733,algorithms 1576 | 1574,1734,algorithms 1577 | 1575,1735,algorithms 1578 | 1576,1736,algorithms 1579 | 1577,1737,algorithms 1580 | 1578,1738,algorithms 1581 | 1579,1739,algorithms 1582 | 1580,1740,algorithms 1583 | 1581,1742,algorithms 1584 | 1582,1743,algorithms 1585 | 1583,1744,algorithms 1586 | 1584,1745,algorithms 1587 | 1585,1746,algorithms 1588 | 1586,1748,algorithms 1589 | 1587,1749,algorithms 1590 | 1588,1750,algorithms 1591 | 1589,1751,algorithms 1592 | 1590,1752,algorithms 1593 | 1591,1753,algorithms 1594 | 1592,1754,algorithms 1595 | 1593,1755,algorithms 1596 | 1594,1756,algorithms 1597 | 1595,1758,algorithms 1598 | 1596,1759,algorithms 1599 | 1597,1760,algorithms 1600 | 1598,1761,algorithms 1601 | 1599,1762,algorithms 1602 | 1600,1763,algorithms 1603 | 1601,1764,algorithms 1604 | 1602,1765,algorithms 1605 | 1603,1766,algorithms 1606 | 1604,1768,algorithms 1607 | 1605,1769,algorithms 1608 | 1606,1770,algorithms 1609 | 1607,1771,algorithms 1610 | 1608,1772,algorithms 1611 | 1609,1773,algorithms 1612 | 1610,1774,algorithms 1613 | 1611,1775,algorithms 1614 | 1612,1776,algorithms 1615 | 1613,1778,algorithms 1616 | 1614,1779,algorithms 1617 | 1615,1780,algorithms 1618 | 1616,1781,algorithms 1619 | 1617,1782,algorithms 1620 | 1618,1784,algorithms 1621 | 1619,1785,algorithms 1622 | 1620,1786,algorithms 1623 | 1621,1787,algorithms 1624 | 1622,1788,algorithms 1625 | 1623,1790,algorithms 1626 | 1624,1791,algorithms 1627 | 1625,1792,algorithms 1628 | 1626,1793,algorithms 1629 | 1627,1794,algorithms 1630 | 1628,1796,algorithms 1631 | 1629,1797,algorithms 1632 | 1630,1798,algorithms 1633 | 1631,1799,algorithms 1634 | 1632,1800,algorithms 1635 | 1633,1801,algorithms 1636 | 1634,1802,algorithms 1637 | 1635,1803,algorithms 1638 | 1636,1804,algorithms 1639 | 1637,1805,algorithms 1640 | 1638,1806,algorithms 1641 | 1639,1807,algorithms 1642 | 1640,1808,algorithms 1643 | 1641,1810,algorithms 1644 | 1642,1812,algorithms 1645 | 1643,1813,algorithms 1646 | 1644,1814,algorithms 1647 | 1645,1815,algorithms 1648 | 1646,1816,algorithms 1649 | 1647,1817,algorithms 1650 | 1648,1818,algorithms 1651 | 1649,1819,algorithms 1652 | 1650,1820,algorithms 1653 | 1651,1822,algorithms 1654 | 1652,1823,algorithms 1655 | 1653,1824,algorithms 1656 | 1654,1825,algorithms 1657 | 1655,1826,algorithms 1658 | 1656,1827,algorithms 1659 | 1657,1828,algorithms 1660 | 1658,1829,algorithms 1661 | 1659,1830,algorithms 1662 | 1660,1832,algorithms 1663 | 1661,1833,algorithms 1664 | 1662,1834,algorithms 1665 | 1663,1835,algorithms 1666 | 1664,1836,algorithms 1667 | 1665,1837,algorithms 1668 | 1666,1838,algorithms 1669 | 1667,1839,algorithms 1670 | 1668,1840,algorithms 1671 | 1669,1842,algorithms 1672 | 1670,1844,algorithms 1673 | 1671,1845,algorithms 1674 | 1672,1846,algorithms 1675 | 1673,1847,algorithms 1676 | 1674,1848,algorithms 1677 | 1675,1849,algorithms 1678 | 1676,1850,algorithms 1679 | 1677,1851,algorithms 1680 | 1678,1852,algorithms 1681 | 1679,1854,algorithms 1682 | 1680,1855,algorithms 1683 | 1681,1856,algorithms 1684 | 1682,1857,algorithms 1685 | 1683,1858,algorithms 1686 | 1684,1859,algorithms 1687 | 1685,1860,algorithms 1688 | 1686,1861,algorithms 1689 | 1687,1862,algorithms 1690 | 1688,1863,algorithms 1691 | 1689,1864,algorithms 1692 | 1690,1865,algorithms 1693 | 1691,1866,algorithms 1694 | 1692,1868,algorithms 1695 | 1693,1869,algorithms 1696 | 1694,1870,algorithms 1697 | 1695,1871,algorithms 1698 | 1696,1872,algorithms 1699 | 1697,1874,algorithms 1700 | 1698,1876,algorithms 1701 | 1699,1877,algorithms 1702 | 1700,1878,algorithms 1703 | 1701,1879,algorithms 1704 | 1702,1880,algorithms 1705 | 1703,1881,algorithms 1706 | 1704,1882,algorithms 1707 | 1705,1883,algorithms 1708 | 1706,1884,algorithms 1709 | 1707,1885,algorithms 1710 | 1708,1886,algorithms 1711 | 1709,1887,algorithms 1712 | 1710,1888,algorithms 1713 | 1711,1889,algorithms 1714 | 1712,1891,algorithms 1715 | 1713,1893,algorithms 1716 | 1714,1894,algorithms 1717 | 1715,1895,algorithms 1718 | 1716,1896,algorithms 1719 | 1717,1897,algorithms 1720 | 1718,1898,algorithms 1721 | 1719,1899,algorithms 1722 | 1720,1900,algorithms 1723 | 1721,1901,algorithms 1724 | 1722,1902,algorithms 1725 | 1723,1903,algorithms 1726 | 1724,1904,algorithms 1727 | 1725,1905,algorithms 1728 | 1726,1906,algorithms 1729 | 1727,1908,algorithms 1730 | 1728,1909,algorithms 1731 | 1729,1910,algorithms 1732 | 1730,1911,algorithms 1733 | 1731,1912,algorithms 1734 | 1732,1913,algorithms 1735 | 1733,1914,algorithms 1736 | 1734,1915,algorithms 1737 | 1735,1916,algorithms 1738 | 1736,1918,algorithms 1739 | 1737,1920,algorithms 1740 | 1738,1921,algorithms 1741 | 1739,1922,algorithms 1742 | 1740,1923,algorithms 1743 | 1741,1924,algorithms 1744 | 1742,1925,algorithms 1745 | 1743,1926,algorithms 1746 | 1744,1927,algorithms 1747 | 1745,1928,algorithms 1748 | 1746,1929,algorithms 1749 | 1747,1930,algorithms 1750 | 1748,1931,algorithms 1751 | 1749,1932,algorithms 1752 | 1750,1933,algorithms 1753 | 1751,1935,algorithms 1754 | 1752,1936,algorithms 1755 | 1753,1937,algorithms 1756 | 1754,1938,algorithms 1757 | 1755,1940,algorithms 1758 | 1756,1941,algorithms 1759 | 1757,1942,algorithms 1760 | 1758,1943,algorithms 1761 | 1759,1944,algorithms 1762 | 1760,1945,algorithms 1763 | 1761,1946,algorithms 1764 | 1762,1947,algorithms 1765 | 1763,1948,algorithms 1766 | 1764,1950,algorithms 1767 | 1765,1952,algorithms 1768 | 1766,1953,algorithms 1769 | 1767,1954,algorithms 1770 | 1768,1955,algorithms 1771 | 1769,1956,algorithms 1772 | 1770,1957,algorithms 1773 | 1771,1958,algorithms 1774 | 1772,1959,algorithms 1775 | 1773,1960,algorithms 1776 | 1774,1961,algorithms 1777 | 1775,1962,algorithms 1778 | 1776,1963,algorithms 1779 | 1777,1964,algorithms 1780 | 1778,1966,algorithms 1781 | 1779,1967,algorithms 1782 | 1780,1968,algorithms 1783 | 1781,1969,algorithms 1784 | 1782,1970,algorithms 1785 | 1783,1971,algorithms 1786 | 1784,1973,algorithms 1787 | 1785,1974,algorithms 1788 | 1786,1975,algorithms 1789 | 1787,1976,algorithms 1790 | 1788,1977,algorithms 1791 | 1789,1979,algorithms 1792 | 1790,1980,algorithms 1793 | 1791,1981,algorithms 1794 | 1792,1982,algorithms 1795 | 1793,1983,algorithms 1796 | 1794,1984,algorithms 1797 | 1795,1985,algorithms 1798 | 1796,1986,algorithms 1799 | 1797,1987,algorithms 1800 | 1798,1989,algorithms 1801 | 1799,1991,algorithms 1802 | 1800,1992,algorithms 1803 | 1801,1993,algorithms 1804 | 1802,1994,algorithms 1805 | 1803,1995,algorithms 1806 | 1804,1996,algorithms 1807 | 1805,1997,algorithms 1808 | 1806,1998,algorithms 1809 | 1807,1999,algorithms 1810 | 1808,2000,algorithms 1811 | 1809,2001,algorithms 1812 | 1810,2002,algorithms 1813 | 1811,2003,algorithms 1814 | 1812,2005,algorithms 1815 | 1813,2006,algorithms 1816 | 1814,2007,algorithms 1817 | 1815,2008,algorithms 1818 | 1816,2009,algorithms 1819 | 1817,2011,algorithms 1820 | 1818,2012,algorithms 1821 | 1819,2013,algorithms 1822 | 1820,2014,algorithms 1823 | 1821,2015,algorithms 1824 | 1822,2016,algorithms 1825 | 1823,2017,algorithms 1826 | 1824,2018,algorithms 1827 | 1825,2019,algorithms 1828 | 1826,2021,algorithms 1829 | 1827,2022,algorithms 1830 | 1828,2023,algorithms 1831 | 1829,2024,algorithms 1832 | 1830,2025,algorithms 1833 | 1831,2027,algorithms 1834 | 1832,2028,algorithms 1835 | 1833,2029,algorithms 1836 | 1834,2030,algorithms 1837 | 1835,2031,algorithms 1838 | 1836,2032,algorithms 1839 | 1837,2033,algorithms 1840 | 1838,2034,algorithms 1841 | 1839,2035,algorithms 1842 | 1840,2036,algorithms 1843 | 1841,2037,algorithms 1844 | 1842,2038,algorithms 1845 | 1843,2039,algorithms 1846 | 1844,2040,algorithms 1847 | 1845,2042,algorithms 1848 | 1846,2043,algorithms 1849 | 1847,2044,algorithms 1850 | 1848,2045,algorithms 1851 | 1849,2046,algorithms 1852 | 1850,2047,algorithms 1853 | 1851,2048,algorithms 1854 | 1852,2049,algorithms 1855 | 1853,2050,algorithms 1856 | 1854,2052,algorithms 1857 | 1855,2053,algorithms 1858 | 1856,2054,algorithms 1859 | 1857,2055,algorithms 1860 | 1858,2056,algorithms 1861 | 1859,2057,algorithms 1862 | 1860,2058,algorithms 1863 | 1861,2059,algorithms 1864 | 1862,2060,algorithms 1865 | 1863,2061,algorithms 1866 | 1864,2062,algorithms 1867 | 1865,2063,algorithms 1868 | 1866,2064,algorithms 1869 | 1867,2065,algorithms 1870 | 1868,2067,algorithms 1871 | 1869,2068,algorithms 1872 | 1870,2069,algorithms 1873 | 1871,2070,algorithms 1874 | 1872,2071,algorithms 1875 | 1873,2073,algorithms 1876 | 1874,2074,algorithms 1877 | 1875,2075,algorithms 1878 | 1876,2076,algorithms 1879 | 1877,2077,algorithms 1880 | 1878,2078,algorithms 1881 | 1879,2079,algorithms 1882 | 1880,2080,algorithms 1883 | 1881,2081,algorithms 1884 | 1882,2083,algorithms 1885 | 1883,2085,algorithms 1886 | 1884,2086,algorithms 1887 | 1885,2087,algorithms 1888 | 1886,2088,algorithms 1889 | 1887,2089,algorithms 1890 | 1888,2090,algorithms 1891 | 1889,2091,algorithms 1892 | 1890,2092,algorithms 1893 | 1891,2093,algorithms 1894 | 1892,2094,algorithms 1895 | 1893,2095,algorithms 1896 | 1894,2096,algorithms 1897 | 1895,2097,algorithms 1898 | 1896,2098,algorithms 1899 | 1897,2099,algorithms 1900 | 1898,2100,algorithms 1901 | 1899,2101,algorithms 1902 | 1900,2102,algorithms 1903 | 1901,2103,algorithms 1904 | 1902,2104,algorithms 1905 | 1903,2105,algorithms 1906 | 1904,2106,algorithms 1907 | 1905,2107,algorithms 1908 | 1906,2108,algorithms 1909 | 1907,2109,algorithms 1910 | 1908,2110,algorithms 1911 | 1909,2111,algorithms 1912 | 1910,2113,algorithms 1913 | 1911,2114,algorithms 1914 | 1912,2115,algorithms 1915 | 1913,2116,algorithms 1916 | 1914,2117,algorithms 1917 | 1915,2119,algorithms 1918 | 1916,2120,algorithms 1919 | 1917,2121,algorithms 1920 | 1918,2122,algorithms 1921 | 1919,2123,algorithms 1922 | 1920,2124,algorithms 1923 | 1921,2125,algorithms 1924 | 1922,2126,algorithms 1925 | 1923,2127,algorithms 1926 | 1924,2128,algorithms 1927 | 1925,2129,algorithms 1928 | 1926,2130,algorithms 1929 | 1927,2131,algorithms 1930 | 1928,2132,algorithms 1931 | 1929,2133,algorithms 1932 | 1930,2134,algorithms 1933 | 1931,2135,algorithms 1934 | 1932,2136,algorithms 1935 | 1933,2137,algorithms 1936 | 1934,2138,algorithms 1937 | 1935,2139,algorithms 1938 | 1936,2140,algorithms 1939 | 1937,2141,algorithms 1940 | 1938,2143,algorithms 1941 | 1939,2144,algorithms 1942 | 1940,2145,algorithms 1943 | 1941,2146,algorithms 1944 | 1942,2147,algorithms 1945 | 1943,2148,algorithms 1946 | 1944,2149,algorithms 1947 | 1945,2150,algorithms 1948 | 1946,2151,algorithms 1949 | 1947,2152,algorithms 1950 | 1948,2154,algorithms 1951 | 1949,2155,algorithms 1952 | 1950,2156,algorithms 1953 | 1951,2157,algorithms 1954 | 1952,2158,algorithms 1955 | 1953,2160,algorithms 1956 | 1954,2161,algorithms 1957 | 1955,2162,algorithms 1958 | 1956,2163,algorithms 1959 | 1957,2164,algorithms 1960 | 1958,2165,algorithms 1961 | 1959,2166,algorithms 1962 | 1960,2167,algorithms 1963 | 1961,2168,algorithms 1964 | 1962,2169,algorithms 1965 | 1963,2170,algorithms 1966 | 1964,2171,algorithms 1967 | 1965,2172,algorithms 1968 | 1966,2174,algorithms 1969 | 1967,2176,algorithms 1970 | 1968,2177,algorithms 1971 | 1969,2178,algorithms 1972 | 1970,2179,algorithms 1973 | 1971,2180,algorithms 1974 | 1972,2181,algorithms 1975 | 1973,2182,algorithms 1976 | 1974,2183,algorithms 1977 | 1975,2184,algorithms 1978 | 1976,2185,algorithms 1979 | 1977,2186,algorithms 1980 | 1978,2187,algorithms 1981 | 1979,2188,algorithms 1982 | 1980,2189,algorithms 1983 | 1981,2190,algorithms 1984 | 1982,2191,algorithms 1985 | 1983,2192,algorithms 1986 | 1984,2193,algorithms 1987 | 1985,2194,algorithms 1988 | 1986,2195,algorithms 1989 | 1987,2196,algorithms 1990 | 1988,2197,algorithms 1991 | 1989,2198,algorithms 1992 | 1990,2200,algorithms 1993 | 1991,2201,algorithms 1994 | 1992,2202,algorithms 1995 | 1993,2203,algorithms 1996 | 1994,2204,algorithms 1997 | 1995,2206,algorithms 1998 | 1996,2207,algorithms 1999 | 1997,2208,algorithms 2000 | 1998,2209,algorithms 2001 | 1999,2210,algorithms 2002 | 2000,2211,algorithms 2003 | 2001,2212,algorithms 2004 | 2002,2213,algorithms 2005 | 2003,2214,algorithms 2006 | 2004,2215,algorithms 2007 | 2005,2216,algorithms 2008 | 2006,2217,algorithms 2009 | 2007,2218,algorithms 2010 | 2008,2219,algorithms 2011 | 2009,2220,algorithms 2012 | 2010,2221,algorithms 2013 | 2011,2222,algorithms 2014 | 2012,2223,algorithms 2015 | 2013,2224,algorithms 2016 | 2014,2225,algorithms 2017 | 2015,2226,algorithms 2018 | 2016,2227,algorithms 2019 | 2017,2229,algorithms 2020 | 2018,2231,algorithms 2021 | 2019,2232,algorithms 2022 | 2020,2233,algorithms 2023 | 2021,2234,algorithms 2024 | 2022,2235,algorithms 2025 | 2023,2236,algorithms 2026 | 2024,2237,algorithms 2027 | 2025,2239,algorithms 2028 | 2026,2240,algorithms 2029 | 2027,2241,algorithms 2030 | 2028,2242,algorithms 2031 | 2029,2243,algorithms 2032 | 2030,2244,algorithms 2033 | 2031,2245,algorithms 2034 | 2032,2246,algorithms 2035 | 2033,2247,algorithms 2036 | 2034,2248,algorithms 2037 | 2035,2249,algorithms 2038 | 2036,2250,algorithms 2039 | 2037,2251,algorithms 2040 | 2038,2254,algorithms 2041 | 2039,2255,algorithms 2042 | 2040,2256,algorithms 2043 | 2041,2257,algorithms 2044 | 2042,2258,algorithms 2045 | 2043,2259,algorithms 2046 | 2044,2260,algorithms 2047 | 2045,2261,algorithms 2048 | 2046,2262,algorithms 2049 | 2047,2263,algorithms 2050 | 2048,2264,algorithms 2051 | 2049,2265,algorithms 2052 | 2050,2266,algorithms 2053 | 2051,2267,algorithms 2054 | 2052,2268,algorithms 2055 | 2053,2269,algorithms 2056 | 2054,2270,algorithms 2057 | 2055,2271,algorithms 2058 | 2056,2272,algorithms 2059 | 2057,2273,algorithms 2060 | 2058,2274,algorithms 2061 | 2059,2275,algorithms 2062 | 2060,2276,algorithms 2063 | 2061,2277,algorithms 2064 | 2062,2278,algorithms 2065 | 2063,2279,algorithms 2066 | 2064,2280,algorithms 2067 | 2065,2281,algorithms 2068 | 2066,2282,algorithms 2069 | 2067,2283,algorithms 2070 | 2068,2284,algorithms 2071 | 2069,2285,algorithms 2072 | 2070,2286,algorithms 2073 | 2071,2287,algorithms 2074 | 2072,2288,algorithms 2075 | 2073,2289,algorithms 2076 | 2074,2290,algorithms 2077 | 2075,2291,algorithms 2078 | 2076,2293,algorithms 2079 | 2077,2294,algorithms 2080 | 2078,2295,algorithms 2081 | 2079,2296,algorithms 2082 | 2080,2297,algorithms 2083 | 2081,2299,algorithms 2084 | 2082,2300,algorithms 2085 | 2083,2301,algorithms 2086 | 2084,2302,algorithms 2087 | 2085,2303,algorithms 2088 | 2086,2304,algorithms 2089 | 2087,2305,algorithms 2090 | 2088,2306,algorithms 2091 | 2089,2307,algorithms 2092 | 2090,2309,algorithms 2093 | 2091,2310,algorithms 2094 | 2092,2311,algorithms 2095 | 2093,2312,algorithms 2096 | 2094,2313,algorithms 2097 | 2095,2315,algorithms 2098 | 2096,2316,algorithms 2099 | 2097,2317,algorithms 2100 | 2098,2318,algorithms 2101 | 2099,2319,algorithms 2102 | 2100,2320,algorithms 2103 | 2101,2321,algorithms 2104 | 2102,2322,algorithms 2105 | 2103,2323,algorithms 2106 | 2104,2325,algorithms 2107 | 2105,2326,algorithms 2108 | 2106,2327,algorithms 2109 | 2107,2328,algorithms 2110 | 2108,2330,algorithms 2111 | 2109,2331,algorithms 2112 | 2110,2332,algorithms 2113 | 2111,2333,algorithms 2114 | 2112,2334,algorithms 2115 | 2113,2335,algorithms 2116 | 2114,2336,algorithms 2117 | 2115,2337,algorithms 2118 | 2116,2338,algorithms 2119 | 2117,2340,algorithms 2120 | 2118,2341,algorithms 2121 | 2119,2342,algorithms 2122 | 2120,2343,algorithms 2123 | 2121,2344,algorithms 2124 | 2122,2345,algorithms 2125 | 2123,2347,algorithms 2126 | 2124,2348,algorithms 2127 | 2125,2349,algorithms 2128 | 2126,2350,algorithms 2129 | 2127,2351,algorithms 2130 | 2128,2352,algorithms 2131 | 2129,2353,algorithms 2132 | 2130,2354,algorithms 2133 | 2131,2355,algorithms 2134 | 2132,2357,algorithms 2135 | 2133,2358,algorithms 2136 | 2134,2359,algorithms 2137 | 2135,2360,algorithms 2138 | 2136,2361,algorithms 2139 | 2137,2363,algorithms 2140 | 2138,2364,algorithms 2141 | 2139,2365,algorithms 2142 | 2140,2366,algorithms 2143 | 2141,2367,algorithms 2144 | 2142,2368,algorithms 2145 | 2143,2369,algorithms 2146 | 2144,2370,algorithms 2147 | 2145,2371,algorithms 2148 | 2146,2373,algorithms 2149 | 2147,2374,algorithms 2150 | 2148,2375,algorithms 2151 | 2149,2376,algorithms 2152 | 2150,2378,algorithms 2153 | 2151,2379,algorithms 2154 | 2152,2380,algorithms 2155 | 2153,2381,algorithms 2156 | 2154,2382,algorithms 2157 | 2155,2383,algorithms 2158 | 2156,2384,algorithms 2159 | 2157,2385,algorithms 2160 | 2158,2386,algorithms 2161 | 2159,2387,algorithms 2162 | 2160,2389,algorithms 2163 | 2161,2390,algorithms 2164 | 2162,2391,algorithms 2165 | 2163,2392,algorithms 2166 | 2164,2393,algorithms 2167 | 2165,2395,algorithms 2168 | 2166,2396,algorithms 2169 | 2167,2397,algorithms 2170 | 2168,2398,algorithms 2171 | 2169,2399,algorithms 2172 | 2170,2400,algorithms 2173 | 2171,2401,algorithms 2174 | 2172,2402,algorithms 2175 | 2173,2403,algorithms 2176 | 2174,2404,algorithms 2177 | 2175,2405,algorithms 2178 | 2176,2406,algorithms 2179 | 2177,2407,algorithms 2180 | 2178,2408,algorithms 2181 | 2179,2409,algorithms 2182 | 2180,2410,algorithms 2183 | 2181,2411,algorithms 2184 | 2182,2412,algorithms 2185 | 2183,2413,algorithms 2186 | 2184,2414,algorithms 2187 | 2185,2415,algorithms 2188 | 2186,2416,algorithms 2189 | 2187,2417,algorithms 2190 | 2188,2418,algorithms 2191 | 2189,2419,algorithms 2192 | 2190,2420,algorithms 2193 | 2191,2421,algorithms 2194 | 2192,2422,algorithms 2195 | 2193,2423,algorithms 2196 | 2194,2424,algorithms 2197 | 2195,2425,algorithms 2198 | 2196,2426,algorithms 2199 | 2197,2427,algorithms 2200 | 2198,2428,algorithms 2201 | 2199,2429,algorithms 2202 | 2200,2430,algorithms 2203 | 2201,2431,algorithms 2204 | 2202,2432,algorithms 2205 | 2203,2433,algorithms 2206 | 2204,2434,algorithms 2207 | 2205,2435,algorithms 2208 | 2206,2436,algorithms 2209 | 2207,2437,algorithms 2210 | 2208,2438,algorithms 2211 | 2209,2439,algorithms 2212 | 2210,2440,algorithms 2213 | 2211,2441,algorithms 2214 | 2212,2442,algorithms 2215 | 2213,2443,algorithms 2216 | 2214,2444,algorithms 2217 | 2215,2445,algorithms 2218 | 2216,2446,algorithms 2219 | 2217,2447,algorithms 2220 | 2218,2448,algorithms 2221 | 2219,2449,algorithms 2222 | 2220,2450,algorithms 2223 | 2221,2451,algorithms 2224 | 2222,2452,algorithms 2225 | 2223,2453,algorithms 2226 | 2224,2454,algorithms 2227 | 2225,2455,algorithms 2228 | 2226,2456,algorithms 2229 | 2227,2457,algorithms 2230 | 2228,2458,algorithms 2231 | 2229,2459,algorithms 2232 | 2230,2460,algorithms 2233 | 2231,2461,algorithms 2234 | 2232,2462,algorithms 2235 | 2233,2463,algorithms 2236 | 2234,2464,algorithms 2237 | 2235,2465,algorithms 2238 | 2236,2466,algorithms 2239 | 2237,2467,algorithms 2240 | 2238,2468,algorithms 2241 | 2239,2469,algorithms 2242 | 2240,2470,algorithms 2243 | 2241,2471,algorithms 2244 | 2242,2472,algorithms 2245 | 2243,2473,algorithms 2246 | 2244,2475,algorithms 2247 | 2245,2476,algorithms 2248 | 2246,2477,algorithms 2249 | 2247,2478,algorithms 2250 | 2248,2479,algorithms 2251 | 2249,2481,algorithms 2252 | 2250,2482,algorithms 2253 | 2251,2483,algorithms 2254 | 2252,2484,algorithms 2255 | 2253,2485,algorithms 2256 | 2254,2486,algorithms 2257 | 2255,2487,algorithms 2258 | 2256,2488,algorithms 2259 | 2257,2489,algorithms 2260 | 2258,2490,algorithms 2261 | 2259,2491,algorithms 2262 | 2260,2492,algorithms 2263 | 2261,2493,algorithms 2264 | 2262,2495,algorithms 2265 | 2263,2496,algorithms 2266 | 2264,2497,algorithms 2267 | 2265,2498,algorithms 2268 | 2266,2499,algorithms 2269 | 2267,2500,algorithms 2270 | 2268,2501,algorithms 2271 | 2269,2502,algorithms 2272 | 2270,2503,algorithms 2273 | 2271,2505,algorithms 2274 | 2272,2506,algorithms 2275 | 2273,2507,algorithms 2276 | 2274,2508,algorithms 2277 | 2275,2509,algorithms 2278 | 2276,2510,algorithms 2279 | 2277,2511,algorithms 2280 | 2278,2512,algorithms 2281 | 2279,2513,algorithms 2282 | 2280,2514,algorithms 2283 | 2281,2515,algorithms 2284 | 2282,2516,algorithms 2285 | 2283,2517,algorithms 2286 | 2284,2518,algorithms 2287 | 2285,2519,algorithms 2288 | 2286,2520,algorithms 2289 | 2287,2521,algorithms 2290 | 2288,2522,algorithms 2291 | 2289,2523,algorithms 2292 | 2290,2524,algorithms 2293 | 2291,2525,algorithms 2294 | 2292,2526,algorithms 2295 | 2293,2527,algorithms 2296 | 2294,2528,algorithms 2297 | 2295,2529,algorithms 2298 | 2296,2530,algorithms 2299 | 2297,2531,algorithms 2300 | 2298,2532,algorithms 2301 | 2299,2533,algorithms 2302 | 2300,2534,algorithms 2303 | 2301,2535,algorithms 2304 | 2302,2536,algorithms 2305 | 2303,2537,algorithms 2306 | 2304,2538,algorithms 2307 | 2305,2539,algorithms 2308 | 2306,2540,algorithms 2309 | 2307,2541,algorithms 2310 | 2308,2542,algorithms 2311 | 2309,2543,algorithms 2312 | 2310,2544,algorithms 2313 | 2311,2545,algorithms 2314 | 2312,2546,algorithms 2315 | 2313,2547,algorithms 2316 | 2314,2548,algorithms 2317 | 2315,2549,algorithms 2318 | 2316,2550,algorithms 2319 | 2317,2551,algorithms 2320 | 2318,2552,algorithms 2321 | 2319,2553,algorithms 2322 | 2320,2554,algorithms 2323 | 2321,2555,algorithms 2324 | 2322,2556,algorithms 2325 | 2323,2557,algorithms 2326 | 2324,2558,algorithms 2327 | 2325,2559,algorithms 2328 | 2326,2560,algorithms 2329 | 2327,2561,algorithms 2330 | 2328,2562,algorithms 2331 | 2329,2563,algorithms 2332 | 2330,2564,algorithms 2333 | 2331,2565,algorithms 2334 | 2332,2566,algorithms 2335 | 2333,2567,algorithms 2336 | 2334,2568,algorithms 2337 | 2335,2569,algorithms 2338 | 2336,2570,algorithms 2339 | 2337,2571,algorithms 2340 | 2338,2572,algorithms 2341 | 2339,2573,algorithms 2342 | 2340,2574,algorithms 2343 | 2341,2575,algorithms 2344 | 2342,2576,algorithms 2345 | 2343,2577,algorithms 2346 | 2344,2578,algorithms 2347 | 2345,2579,algorithms 2348 | 2346,2580,algorithms 2349 | 2347,2581,algorithms 2350 | 2348,2582,algorithms 2351 | 2349,2583,algorithms 2352 | 2350,2584,algorithms 2353 | 2351,2585,algorithms 2354 | 2352,2586,algorithms 2355 | 2353,2587,algorithms 2356 | 2354,2588,algorithms 2357 | 2355,2589,algorithms 2358 | 2356,2590,algorithms 2359 | 2357,2591,algorithms 2360 | 2358,2592,algorithms 2361 | 2359,2593,algorithms 2362 | 2360,2594,algorithms 2363 | 2361,2595,algorithms 2364 | 2362,2596,algorithms 2365 | 2363,2597,algorithms 2366 | 2364,2598,algorithms 2367 | 2365,2599,algorithms 2368 | 2366,2600,algorithms 2369 | 2367,2601,algorithms 2370 | 2368,2602,algorithms 2371 | 2369,2603,algorithms 2372 | 2370,2604,algorithms 2373 | 2371,2605,algorithms 2374 | 2372,2606,algorithms 2375 | 2373,2607,algorithms 2376 | 2374,2608,algorithms 2377 | 2375,2609,algorithms 2378 | 2376,2610,algorithms 2379 | 2377,2611,algorithms 2380 | 2378,2612,algorithms 2381 | 2379,2613,algorithms 2382 | 2380,2614,algorithms 2383 | 2381,2615,algorithms 2384 | 2382,2616,algorithms 2385 | 2383,2617,algorithms 2386 | 2384,2638,algorithms 2387 | 2385,2639,algorithms 2388 | 2386,2640,algorithms 2389 | 2387,2641,algorithms 2390 | 2388,2642,algorithms 2391 | 2389,2643,algorithms 2392 | 2390,2644,algorithms 2393 | 2391,2645,algorithms 2394 | 2392,2646,algorithms 2395 | 2393,2647,algorithms 2396 | 2394,2651,algorithms 2397 | 2395,2652,algorithms 2398 | 2396,2653,algorithms 2399 | 2397,2654,algorithms 2400 | 2398,2655,algorithms 2401 | 2399,2656,algorithms 2402 | 2400,2657,algorithms 2403 | 2401,2658,algorithms 2404 | 2402,2659,algorithms 2405 | 2403,2660,algorithms 2406 | 2404,2661,algorithms 2407 | 2405,2662,algorithms 2408 | 2406,2663,algorithms 2409 | 2407,2664,algorithms 2410 | 2408,2670,algorithms 2411 | 2409,2671,algorithms 2412 | 2410,2672,algorithms 2413 | 2411,2673,algorithms 2414 | 2412,2674,algorithms 2415 | 2413,2678,algorithms 2416 | 2414,2679,algorithms 2417 | 2415,2680,algorithms 2418 | 2416,2681,algorithms 2419 | 2417,2682,algorithms 2420 | 2418,2683,algorithms 2421 | 2419,2684,algorithms 2422 | 2420,2685,algorithms 2423 | 2421,2689,algorithms 2424 | 2422,2696,algorithms 2425 | 2423,2697,algorithms 2426 | 2424,2698,algorithms 2427 | 2425,2699,algorithms 2428 | 2426,2702,algorithms 2429 | 2427,2706,algorithms 2430 | 2428,2707,algorithms 2431 | 2429,2708,algorithms 2432 | 2430,2709,algorithms 2433 | 2431,2710,algorithms 2434 | 2432,2711,algorithms 2435 | 2433,2712,algorithms 2436 | 2434,2713,algorithms 2437 | 2435,2714,algorithms 2438 | 2436,2716,algorithms 2439 | 2437,2717,algorithms 2440 | 2438,2718,algorithms 2441 | 2439,2719,algorithms 2442 | 2440,2728,algorithms 2443 | 2441,2729,algorithms 2444 | 2442,2730,algorithms 2445 | 2443,2731,algorithms 2446 | 2444,2732,algorithms 2447 | 2445,2733,algorithms 2448 | 2446,2734,algorithms 2449 | 2447,2735,algorithms 2450 | 2448,2736,algorithms 2451 | 2449,2737,algorithms 2452 | 2450,2739,algorithms 2453 | 2451,2740,algorithms 2454 | 2452,2741,algorithms 2455 | 2453,2742,algorithms 2456 | 2454,2743,algorithms 2457 | 2455,2744,algorithms 2458 | 2456,2745,algorithms 2459 | 2457,2746,algorithms 2460 | 2458,2747,algorithms 2461 | 2459,2748,algorithms 2462 | 2460,2749,algorithms 2463 | 2461,2750,algorithms 2464 | 2462,2751,algorithms 2465 | 2463,2753,algorithms 2466 | 2464,2760,algorithms 2467 | 2465,2761,algorithms 2468 | 2466,2762,algorithms 2469 | 2467,2763,algorithms 2470 | 2468,2764,algorithms 2471 | 2469,175,database 2472 | 2470,176,database 2473 | 2471,177,database 2474 | 2472,178,database 2475 | 2473,180,database 2476 | 2474,181,database 2477 | 2475,182,database 2478 | 2476,183,database 2479 | 2477,184,database 2480 | 2478,185,database 2481 | 2479,196,database 2482 | 2480,197,database 2483 | 2481,262,database 2484 | 2482,511,database 2485 | 2483,512,database 2486 | 2484,534,database 2487 | 2485,550,database 2488 | 2486,569,database 2489 | 2487,570,database 2490 | 2488,571,database 2491 | 2489,574,database 2492 | 2490,577,database 2493 | 2491,578,database 2494 | 2492,579,database 2495 | 2493,580,database 2496 | 2494,584,database 2497 | 2495,585,database 2498 | 2496,586,database 2499 | 2497,595,database 2500 | 2498,596,database 2501 | 2499,597,database 2502 | 2500,601,database 2503 | 2501,602,database 2504 | 2502,603,database 2505 | 2503,607,database 2506 | 2504,608,database 2507 | 2505,610,database 2508 | 2506,612,database 2509 | 2507,613,database 2510 | 2508,614,database 2511 | 2509,615,database 2512 | 2510,618,database 2513 | 2511,619,database 2514 | 2512,620,database 2515 | 2513,626,database 2516 | 2514,627,database 2517 | 2515,1045,database 2518 | 2516,1050,database 2519 | 2517,1068,database 2520 | 2518,1069,database 2521 | 2519,1070,database 2522 | 2520,1075,database 2523 | 2521,1076,database 2524 | 2522,1077,database 2525 | 2523,1082,database 2526 | 2524,1083,database 2527 | 2525,1084,database 2528 | 2526,1097,database 2529 | 2527,1098,database 2530 | 2528,1107,database 2531 | 2529,1112,database 2532 | 2530,1113,database 2533 | 2531,1126,database 2534 | 2532,1127,database 2535 | 2533,1132,database 2536 | 2534,1141,database 2537 | 2535,1142,database 2538 | 2536,1148,database 2539 | 2537,1149,database 2540 | 2538,1158,database 2541 | 2539,1159,database 2542 | 2540,1164,database 2543 | 2541,1173,database 2544 | 2542,1174,database 2545 | 2543,1179,database 2546 | 2544,1193,database 2547 | 2545,1194,database 2548 | 2546,1204,database 2549 | 2547,1205,database 2550 | 2548,1211,database 2551 | 2549,1212,database 2552 | 2550,1225,database 2553 | 2551,1241,database 2554 | 2552,1251,database 2555 | 2553,1264,database 2556 | 2554,1270,database 2557 | 2555,1280,database 2558 | 2556,1285,database 2559 | 2557,1294,database 2560 | 2558,1303,database 2561 | 2559,1308,database 2562 | 2560,1321,database 2563 | 2561,1322,database 2564 | 2562,1327,database 2565 | 2563,1336,database 2566 | 2564,1341,database 2567 | 2565,1350,database 2568 | 2566,1355,database 2569 | 2567,1364,database 2570 | 2568,1369,database 2571 | 2569,1378,database 2572 | 2570,1384,database 2573 | 2571,1393,database 2574 | 2572,1398,database 2575 | 2573,1407,database 2576 | 2574,1412,database 2577 | 2575,1421,database 2578 | 2576,1435,database 2579 | 2577,1440,database 2580 | 2578,1445,database 2581 | 2579,1454,database 2582 | 2580,1459,database 2583 | 2581,1468,database 2584 | 2582,1479,database 2585 | 2583,1484,database 2586 | 2584,1495,database 2587 | 2585,1501,database 2588 | 2586,1511,database 2589 | 2587,1517,database 2590 | 2588,1527,database 2591 | 2589,1532,database 2592 | 2590,1543,database 2593 | 2591,1549,database 2594 | 2592,1555,database 2595 | 2593,1565,database 2596 | 2594,1571,database 2597 | 2595,1581,database 2598 | 2596,1587,database 2599 | 2597,1596,database 2600 | 2598,1607,database 2601 | 2599,1613,database 2602 | 2600,1623,database 2603 | 2601,1633,database 2604 | 2602,1635,database 2605 | 2603,1645,database 2606 | 2604,1651,database 2607 | 2605,1661,database 2608 | 2606,1667,database 2609 | 2607,1677,database 2610 | 2608,1683,database 2611 | 2609,1693,database 2612 | 2610,1699,database 2613 | 2611,1709,database 2614 | 2612,1715,database 2615 | 2613,1729,database 2616 | 2614,1731,database 2617 | 2615,1741,database 2618 | 2616,1747,database 2619 | 2617,1757,database 2620 | 2618,1767,database 2621 | 2619,1777,database 2622 | 2620,1783,database 2623 | 2621,1789,database 2624 | 2622,1795,database 2625 | 2623,1809,database 2626 | 2624,1811,database 2627 | 2625,1821,database 2628 | 2626,1831,database 2629 | 2627,1841,database 2630 | 2628,1843,database 2631 | 2629,1853,database 2632 | 2630,1867,database 2633 | 2631,1873,database 2634 | 2632,1875,database 2635 | 2633,1890,database 2636 | 2634,1892,database 2637 | 2635,1907,database 2638 | 2636,1917,database 2639 | 2637,1919,database 2640 | 2638,1934,database 2641 | 2639,1939,database 2642 | 2640,1949,database 2643 | 2641,1951,database 2644 | 2642,1965,database 2645 | 2643,1972,database 2646 | 2644,1978,database 2647 | 2645,1988,database 2648 | 2646,1990,database 2649 | 2647,2004,database 2650 | 2648,2010,database 2651 | 2649,2020,database 2652 | 2650,2026,database 2653 | 2651,2041,database 2654 | 2652,2051,database 2655 | 2653,2066,database 2656 | 2654,2072,database 2657 | 2655,2082,database 2658 | 2656,2084,database 2659 | 2657,2112,database 2660 | 2658,2118,database 2661 | 2659,2142,database 2662 | 2660,2153,database 2663 | 2661,2159,database 2664 | 2662,2173,database 2665 | 2663,2175,database 2666 | 2664,2199,database 2667 | 2665,2205,database 2668 | 2666,2228,database 2669 | 2667,2230,database 2670 | 2668,2238,database 2671 | 2669,2252,database 2672 | 2670,2253,database 2673 | 2671,2292,database 2674 | 2672,2298,database 2675 | 2673,2308,database 2676 | 2674,2314,database 2677 | 2675,2324,database 2678 | 2676,2329,database 2679 | 2677,2339,database 2680 | 2678,2346,database 2681 | 2679,2356,database 2682 | 2680,2362,database 2683 | 2681,2372,database 2684 | 2682,2377,database 2685 | 2683,2388,database 2686 | 2684,2394,database 2687 | 2685,2474,database 2688 | 2686,2480,database 2689 | 2687,2494,database 2690 | 2688,2504,database 2691 | 2689,2668,database 2692 | 2690,2669,database 2693 | 2691,2686,database 2694 | 2692,2687,database 2695 | 2693,2688,database 2696 | 2694,2701,database 2697 | 2695,2720,database 2698 | 2696,2738,database 2699 | 2697,2752,database 2700 | 2698,192,shell 2701 | 2699,193,shell 2702 | 2700,194,shell 2703 | 2701,195,shell 2704 | 2702,1114,concurrency 2705 | 2703,1115,concurrency 2706 | 2704,1116,concurrency 2707 | 2705,1117,concurrency 2708 | 2706,1188,concurrency 2709 | 2707,1195,concurrency 2710 | 2708,1226,concurrency 2711 | 2709,1242,concurrency 2712 | 2710,1279,concurrency 2713 | --------------------------------------------------------------------------------