diff --git a/.github/workflows/leetcode_directory_writer.yml b/.github/workflows/leetcode_directory_writer.yml new file mode 100644 index 00000000000..7a29e114804 --- /dev/null +++ b/.github/workflows/leetcode_directory_writer.yml @@ -0,0 +1,30 @@ +# The objective of this GitHub Action is to update the leetcode DIRECTORY.md file (if needed) +# when doing a git push +name: leetcode_directory_writer +on: + pull_request: + paths: + - 'leetcode/src/**.cpp' +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Add python dependencies + run: | + pip install requests + - name: Write LeetCode DIRECTORY.md + run: | + python3 scripts/leetcode_directory_md.py 2>&1 | tee leetcode/DIRECTORY.md + - name: Commit and push changes + uses: stefanzweifel/git-auto-commit-action@v4 + id: commit-push + with: + commit_message: 'docs: updating `leetcode/DIRECTORY.md`' + branch: 'leetcode-directory-${{ github.sha }}' + create_branch: true diff --git a/leetcode/README.md b/leetcode/README.md new file mode 100644 index 00000000000..5d651b16a4e --- /dev/null +++ b/leetcode/README.md @@ -0,0 +1,69 @@ +# 📚 Contributing 📚 + +We're glad you're interested in adding C++ LeetCode solutions to the repository.\ +Here we'll be explaining how to contribute to LeetCode solutions properly. + +## 💻 Cloning/setting up the project 💻 + +First off, you'll need to fork the repository [**here**](https://github.com/TheAlgorithms/C-Plus-Plus/fork).\ +Then, you'll need to clone the repository to your local machine. + +```bash +git clone https://github.com/your-username/C-Plus-Plus.git +``` + +After that, you'll need to create a new branch for your solution. + +```bash +git checkout -b solution/your-solution-name +``` + +## 📝 Adding a new solution 📝 + +All LeetCode problems can be found [**here**](https://leetcode.com/problemset/all/).\ +If you have a solution to any of these problems (which are not being **repeated**, that's great! Here are the steps: + +1. Add a new file in `leetcode/src` with the number of the problem. + - For example: if the problem's number is 98, the filename should be `98.cpp`. +2. Provide a small description of the solution at the top of the file. A function should go below that. For example: + +```c +/** + * Return an vector of vector of size returnSize. + * The sizes of the vectors are returned as returnColumnSizes vector. + * Note: Both returned vector and columnSizes vector must be dynamically allocated, assume caller calls free. + */ +``` + +3. Do not provide a `main` function. Use the required standalone functions instead. +4. Doxygen documentation isn't used in LeetCode solutions. Simple/small documentation or comments should be fine. +5. Please include dependency libraries/headers such as ``, `` along with the `Solution` class to the problem. This will help the CI to succeed without the dependency errors. + +> **Note** +> There was a requirement to update the `leetcode/DIRECTORY.md` file with details of the solved problem. It's not required anymore. The information about the problem is fetched automatically throughout the LeetCode API. + +## 📦 Committing your changes 📦 + +Once you're done with adding a new LeetCode solution, it's time we make a pull request. + +1. First, stage your changes. + +```bash +git add leetcode/src/98.cpp # Use `git add .` to stage all changes. +``` + +2. Then, commit your changes. + +```bash +git commit -m "feat: add LeetCode problem 98" -m "Commit description" # Optional +``` + +3. Finally, push your changes to your forked repository. + +```bash +git push origin solution/your-solution-name:solution/your-solution-name +``` + +4. You're done now! You just have to make a [**pull request**](https://github.com/TheAlgorithms/C-Plus-Plus/compare). 🎉 + +If you need any help, don't hesitate to ask and join our [**Discord server**](https://the-algorithms.com/discord)! 🙂 diff --git a/leetcode/src/1.cpp b/leetcode/src/1.cpp new file mode 100644 index 00000000000..683757c1dc9 --- /dev/null +++ b/leetcode/src/1.cpp @@ -0,0 +1,27 @@ +/* + * Given an array of integers nums and an integer target, return indices of the + * two numbers such that they add up to target. + * You may assume that each input would have exactly one solution, and you may not use the same element twice. + */ + +#include +#include +class Solution { +public: + std::vector twoSum(std::vector& nums, int target) { + std::unordered_map mp; // value:index + std::vector res; + + for (int i = 0; i < nums.size(); i++) { + int diff = target - nums[i]; + + if (mp.find(diff) != mp.end()) { + res.push_back(mp[diff]); + res.push_back(i); + return res; + } + mp[nums[i]] = i; + } + return res; + } +}; diff --git a/leetcode/src/2.cpp b/leetcode/src/2.cpp new file mode 100644 index 00000000000..bc9573f9430 --- /dev/null +++ b/leetcode/src/2.cpp @@ -0,0 +1,40 @@ +/* You are given two non - empty linked lists representing two non - negative integers. + * The digits are stored in reverse order, and each of their nodes contains a single digit. + * Add the two numbersand return the sum as a linked list. + */ + +#include + + /* + * Definition for singly-linked list. + */ +struct ListNode { + int val; + ListNode *next; + explicit ListNode() : val(0), next(nullptr) {} + explicit ListNode(int x) : val(x), next(nullptr) {} + explicit ListNode(int x, ListNode *next) : val(x), next(next) {} +}; + +class Solution { +public: +ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { + int carry = 0; + std::unique_ptr head(new ListNode(0)); + ListNode* sum = head.get(); + + while(l1 || l2) { + int val = carry + (l1 ? l1->val : 0) + (l2 ? l2->val : 0); + carry = val/10; + sum->next = new ListNode(val%10); + sum = sum->next; + l1 = (l1 ? l1->next : nullptr); + l2 = (l2 ? l2->next : nullptr); + } + if(carry){ + sum->next = new ListNode(carry); + } + + return head->next; +} +}; diff --git a/scripts/leetcode_directory_md.py b/scripts/leetcode_directory_md.py new file mode 100644 index 00000000000..4fa40728778 --- /dev/null +++ b/scripts/leetcode_directory_md.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +from dataclasses import dataclass +from os import listdir +from pathlib import Path + +import requests + + +@dataclass +class Task: + """The task dataclass. Container for task info""" + + id: str + title: str + solution: str + difficulty: str + + +def fetch_leetcode_folder_tasks(solutions_folder: Path) -> list[Task]: + """Fetch leetcode tasks from the Leetcode""" + + # Fetch tasks info from the leetcode API. + resp = requests.get("https://leetcode.com/api/problems/algorithms/", timeout=10) + content_dict = resp.json() + + raw_tasks_id_dict = {} + + for task in content_dict["stat_status_pairs"]: + task_stat = task["stat"] + raw_tasks_id_dict[str(task_stat["frontend_question_id"])] = task + + # Generate result tasks info to be inserted into the document + tasks_list = [] + + difficulty = {1: "Easy", 2: "Medium", 3: "Hard"} + + for fl in listdir(solutions_folder): + task_id = fl.split(".")[0] + + raw_task = raw_tasks_id_dict.get(task_id, None) + if raw_task is None: + continue + + raw_task_stat = raw_task["stat"] + tasks_list.append( + Task( + id=f'{raw_task_stat["frontend_question_id"]}', + title=f'[{raw_task_stat["question__title"]}](https://leetcode.com/problems/{raw_task_stat["question__title_slug"]})', + solution=f"[C++](./src/{fl})", + difficulty=f'{difficulty.get(raw_task["difficulty"]["level"], "")}', + ) + ) + + return tasks_list + + +HEADER_ID = "#" +HEADER_TITLE = "Title" +HEADER_SOLUTION = "Solution" +HEADER_DIFFICULTY = "Difficulty" +SEPARATOR = "-" + + +def print_directory_md(tasks_list: list[Task]) -> None: + """Print tasks into the stdout""" + + def get_max_len(get_item): + return max(list(map(lambda x: len(get_item(x)), tasks_list))) + + id_max_length = max(get_max_len(lambda x: x.id), len(HEADER_ID)) + title_max_length = max(get_max_len(lambda x: x.title), len(HEADER_TITLE)) + solution_max_length = max(get_max_len(lambda x: x.solution), len(HEADER_SOLUTION)) + difficulty_max_length = max( + get_max_len(lambda x: x.difficulty), len(HEADER_DIFFICULTY) + ) + + def formatted_string(header, title, solution, difficulty): + return ( + f"| {header.rjust(id_max_length)} " + + f"| {title.ljust(title_max_length)} " + + f"| {solution.ljust(solution_max_length)} " + + f"| {difficulty.ljust(difficulty_max_length)} |" + ) + + tasks_rows = [] + + tasks_rows.append( + formatted_string(HEADER_ID, HEADER_TITLE, HEADER_SOLUTION, HEADER_DIFFICULTY) + ) + tasks_rows.append( + formatted_string( + id_max_length * SEPARATOR, + title_max_length * SEPARATOR, + solution_max_length * SEPARATOR, + difficulty_max_length * SEPARATOR, + ) + ) + + tasks_list.sort(key=lambda x: int(x.id.strip())) + + for task in tasks_list: + tasks_rows.append( + formatted_string(task.id, task.title, task.solution, task.difficulty) + ) + + print( + """ +# LeetCode + +### LeetCode Algorithm +""" + ) + + for item in tasks_rows: + print(item) + + +if __name__ == "__main__": + top_dir = Path(".") + solutions_folder = top_dir / "leetcode" / "src" + + tasks_list = fetch_leetcode_folder_tasks(solutions_folder) + print_directory_md(tasks_list)