├── 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 | [](https://leetscrape.nikhilravi.com) [](https://pypi.org/project/leetscrape/) [](https://codecov.io/gh/nikhil-ravi/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 | [](https://leetscrape.nikhilravi.com) [](https://pypi.org/project/leetscrape/) [](https://codecov.io/gh/nikhil-ravi/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 |
--------------------------------------------------------------------------------