diff --git a/Makefile b/Makefile index 6d59000..124740b 100644 --- a/Makefile +++ b/Makefile @@ -265,8 +265,27 @@ stats: # Update README badges with current problem counts .PHONY: update-badges update-badges: - @echo "$(call color_green,Updating README badges...)" + @echo "Updating README badges..." @./scripts/update_badges.sh + @echo "$(call color_green,README badges updated.)" + +# README Generation +.PHONY: readme +readme: ## Generate README from problem configurations + @$(PYTHON) scripts/generate_readme.py + +.PHONY: readme-check +readme-check: ## Check if README is up to date + @echo "Checking if README is up to date..." + @cp README.md README.md.backup + @$(PYTHON) scripts/generate_readme.py > /dev/null + @if ! diff -q README.md README.md.backup > /dev/null; then \ + echo "$(call color_yellow,README is out of date. Run 'make readme' to update.)"; \ + mv README.md.backup README.md; \ + else \ + echo "$(call color_green,README is up to date.)"; \ + rm README.md.backup; \ + fi # Debug Google Test configuration .PHONY: debug-gtest @@ -334,6 +353,8 @@ help: @echo "$(call color_yellow,Utility Targets:)" @echo " clean - Clean build artifacts" @echo " stats - Show project statistics" + @echo " readme - Generate README from problem configurations" + @echo " readme-check - Check if README is up to date" @echo " update-badges - Update README badges with current problem counts" @echo " debug-gtest - Debug Google Test configuration" @echo " help - Show this help message" diff --git a/README.md b/README.md index 1578f74..c7a7e66 100644 --- a/README.md +++ b/README.md @@ -90,94 +90,27 @@ make lint-python # Lint Python files with ruff - [Intervals](#intervals) - [Linked List](#linked-list) - [Binary Tree General](#binary-tree-general) +- [Binary Tree BFS](#binary-tree-bfs) - [Binary Search Tree](#binary-search-tree) - [Graph General](#graph-general) +- [Dynamic Programming](#dynamic-programming) +- [Backtracking](#backtracking) +- [Heap](#heap) +- [Greedy](#greedy) +- [Trie](#trie) ## Arrays & Hashing -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------- | ---------- | ---------- | --- | ---------------------------------------------------------------------------------- | -| 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | [Python](./python/problems/easy/two_sum.py), [C++](./cpp/problems/easy/two_sum/two_sum.cpp) | _O(n)_ | _O(n)_ | Easy | | | -| 49 | [Group Anagrams](https://leetcode.com/problems/group-anagrams/) | [Python](./python/problems/medium/group_anagrams.py) | _O(NK)_ | _O(NK)_ | Medium | | _N_ is the number of strings and _K_ is the maximum length of a single string | -| 88 | [Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/) | [Python](./python/problems/easy/merge_sorted_array.py) | _O(n + m)_ | _O(1)_ | Easy | | Two-Pointers, Reverse | -| 128 | [Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/) | [Python](./python/problems/medium/longest_consecutive_sequence.py) | _O(n)_ | _O(n)_ | Medium | | Tricky solution! | -| 135 | [Candy](https://leetcode.com/problems/candy/) | [Python](./python/problems/hard/candy.py) | _O(n)_ | _O(n)_ | Hard | | Enjoyed solving it! | -| 217 | [Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) | [Python](./python/problems/easy/contains_duplicate.py) | _O(n)_ | _O(n)_ | Easy | | | -| 238 | [Product of Array Except Self](https://leetcode.com/problems/product-of-array-except-self/) | [Python](./python/problems/medium/product_of_array_except_self.py) | _O(n)_ | _O(1)_ | Medium | | Interesting solution! | -| 242 | [Valid Anagram](https://leetcode.com/problems/valid-anagram/) | [Python](./python/problems/easy/valid_anagram.py) | _O(n)_ | _O(n)_ | Easy | | Given Unicode characters support for Python3, the follow-up question is irrelevant | -| 271 | [Encode and Decode Strings](https://leetcode.com/problems/encode-and-decode-strings/) | [Python](./python/problems/medium/encode_and_decode_strings.py) | _O(n)_ | _O(n)_ | Medium | | -| 347 | [Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) | [Python](./python/problems/medium/top_k_frequent_elements.py) | _O(N\*log(K))_ | _O(N + K)_ | Medium | | Requires MinHeap | -| 383 | [Ransom Note](https://leetcode.com/problems/ransom-note/) | [Python](./python/problems/easy/ransom_note.py) | _O(n)_ | _O(1)_ | Easy | | Fixed List | +| # | Title | Solution | Time | Space | Difficulty | Tag | Note | +|---|-------|----------|------|-------|------------|-----|------| +| 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | [Python](./problems/two_sum/two_sum.py), [C++](./problems/two_sum/two_sum.cc) | _O(n)_ | _O(n)_ | Easy | | | -## Two-Pointers +## Two Pointers -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------- | ---------- | --- | ----------------------------------------------------------------------------------------- | -| 11 | [Container With Most Water](https://leetcode.com/problems/container-with-most-water/) | [Python](./python/problems/medium/container_with_most_water.py) | _O(n)_ | _O(1)_ | Medium | | | -| 15 | [3Sum](https://leetcode.com/problems/3sum/) | [Python](./python/problems/medium/three_sum.py) | _O(n^2)_ | _O(1)_ | Medium | | | -| 42 | [Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) | [Python _O(n)_](./python/problems/hard/trapping_rain_water_o_n.py), [Python _O(1)_](./python/problems/hard/trapping_rain_water_o_1.py) | _O(n)_ | _O(n)_ or _O(1)_ | Hard | | Initially proposed an O(n) space complexity solution, but discovered an O(1) alternative. | -| 125 | [Valid Palindrome](https://leetcode.com/problems/valid-palindrome/) | [Python](./python/problems/easy/valid_palindrome.py) | _O(n)_ | _O(1)_ | Easy | | | -| 167 | [Two Sum II - Input Array is Sorted](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/) | [Python](./python/problems/medium/two_sum_ii_input_array_is_sorted.py) | _O(n)_ | _O(1)_ | Medium | | | +| # | Title | Solution | Time | Space | Difficulty | Tag | Note | +|---|-------|----------|------|-------|------------|-----|------| +| 125 | [Valid Palindrome](https://leetcode.com/problems/valid-palindrome/) | [Python](./problems/valid_palindrome/valid_palindrome.py), [C++](./problems/valid_palindrome/valid_palindrome.cc) | _O(n)_ | _O(1)_ | Easy | | | -## Sliding-Window +## License -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------- | ----------------------------------------------------------------------------------- | ---------- | --- | ---------------------------------------------------------------------------- | -| 3 | [Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) | [Python](./python/problems/medium/longest_substring_without_repeating_characters.py) | _O(n)_ | _O(min(n, m))_, _n_ being size of the string and _m_ being the size of the alphabet | Medium | | A better solution would be to jump to the point where we have a valid string | -| 76 | [Minimum Window Substring](https://leetcode.com/problems/minimum-window-substring/) | [Python](./python/problems/hard/minimum_window_substring.py) | _O(m + n)_, _m_ being size of `s` and _n_ the size of `t` | _O(l)_, _l_ being the number of unique characters in `t` | Hard | | | -| 121 | [Best Time to But and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) | [Python](./python/problems/easy/best_time_to_buy_and_sell_stock.py) | _O(n)_ | _O(1)_ | Easy | | | -| 209 | [Minimum Size Subarray Sum](https://leetcode.com/problems/minimum-size-subarray-sum/) | [Python](./python/problems/medium/minimum_size_subarray_sum.py) | _O(n)_ | _O(1)_ | Medium | | | -| 239 | [Sliding Window Maximum](https://leetcode.com/problems/sliding-window-maximum/) | [Python](./python/problems/hard/sliding_window_maximum.py) | _O(n)_, _n_ being the length of `nums` | _O(k)_, _k_ being the window size | Hard | | | -| 424 | [Longest Repeating Character Replacement](https://leetcode.com/problems/longest-repeating-character-replacement/) | [Python](./python/problems/medium/longest_repeating_character_replacement.py) | _O(n)_ | _O(1)_ | Medium | | | -| 567 | [Permutation in String](https://leetcode.com/problems/permutation-in-string/) | [Python](./python/problems/medium/permutation_in_string.py) | _O(n)_, _n_ being the length of s2 | _O(k)_, _k_ being the length of s1 | Medium | | | - -## Stack - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------- | ------ | ---------- | --- | ------------------------------- | -| 20 | [Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) | [Python](./python/problems/easy/valid_parentheses.py) | _O(n)_ | _O(n)_ | Easy | | | -| 22 | [Generate Parentheses](https://leetcode.com/problems/generate-parentheses/) | [Python](./python/problems/medium/generate_parentheses.py) | _O(4^n/sqrt(n))_ | _O(n)_ | Medium | | | -| 150 | [Evaluate Reverse Polish Notation](https://leetcode.com/problems/evaluate-reverse-polish-notation/) | [Python](./python/problems/medium/evaluate_reverse_polish_notation.py) | _O(n)_ | _O(n)_ | Medium | | | -| 155 | [Min Stack](https://leetcode.com/problems/min-stack/) | [Python](./python/problems/medium/min_stack.py) | _O(1)_ | _O(1)_ | Medium | | Tuple in stack is interesting ! | - -## Matrix - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | ----------------------------------------------------------- | -------------------------------------------------- | ------ | ------ | ---------- | --- | ---- | -| 36 | [Valid Sudoku](https://leetcode.com/problems/valid-sudoku/) | [Python](./python/problems/medium/valid_sudoku.py) | _O(1)_ | _O(1)_ | Medium | | | - -## Intervals - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | --------------------------------------------------------------- | -------------------------------------------------- | ------ | ------ | ---------- | --- | ---- | -| 228 | [Summary Ranges](https://leetcode.com/problems/summary-ranges/) | [Python](./python/problems/easy/summary_ranges.py) | _O(n)_ | _O(n)_ | Easy | | | - -## Linked-List - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | --------------------------------------------------------------------- | ----------------------------------------------------- | ------ | ------ | ---------- | --- | ---- | -| 141 | [Linked List Cycle](https://leetcode.com/problems/linked-list-cycle/) | [Python](./python/problems/easy/linked_list_cycle.py) | _O(n)_ | _O(1)_ | Easy | | | - -## Binary-Tree-General - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------ | ------ | ---------- | --- | ---------------- | -| 104 | [Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/) | [Python](./python/problems/easy//maximum_depth_of_binary_tree.py) | _O(n)_ | _O(1)_ | Easy | DFS | Use FIFO for BFS | - -## Binary-Tree-BFS - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------ | ------------------------------------------------------ | ---------- | --- | ---- | -| 199 | [Binary Tree Right Side View](https://leetcode.com/problems/binary-tree-right-side-view/) | [Python](./python/problems/medium/binary_tree_right_side_view.py) | _O(n)_ | _O(w)_ where w is the maximum width of the binary tree | Medium | | | - -## Binary-Search-Tree - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------ | ------ | ---------- | --- | ------------------ | -| 530 | [Minimum Absolute Difference in BST](https://leetcode.com/problems/minimum-absolute-difference-in-bst/) | [Python](./python/problems/easy/minimum_absolute_difference_in_bst.py) | _O(n)_ | _O(1)_ | Easy | | In-order traversal | - -## Graph-General - -| # | Title | Solution | Time | Space | Difficulty | Tag | Note | -| --- | --------------------------------------------------------------------- | ------------------------------------------------------- | ----------- | ------ | ---------- | --- | ---- | -| 200 | [Number of Islands](https://leetcode.com/problems/number-of-islands/) | [Python](./python/problems/medium/number_of_islands.py) | _O(n \* m)_ | _O(1)_ | Medium | | | +This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/config/difficulties.yml b/config/difficulties.yml new file mode 100644 index 0000000..82f9fa5 --- /dev/null +++ b/config/difficulties.yml @@ -0,0 +1,4 @@ +difficulties: + - easy + - medium + - hard diff --git a/config/tags.yml b/config/tags.yml new file mode 100644 index 0000000..fc77d5c --- /dev/null +++ b/config/tags.yml @@ -0,0 +1,17 @@ +tags: + - "Arrays & Hashing" + - "Two Pointers" + - "Sliding Window" + - "Stack" + - "Matrix" + - "Intervals" + - "Linked List" + - "Binary Tree General" + - "Binary Tree BFS" + - "Binary Search Tree" + - "Graph General" + - "Dynamic Programming" + - "Backtracking" + - "Heap" + - "Greedy" + - "Trie" diff --git a/problems/two_sum/config.yml b/problems/two_sum/config.yml new file mode 100644 index 0000000..cd0641e --- /dev/null +++ b/problems/two_sum/config.yml @@ -0,0 +1,17 @@ +problem: + number: 1 + title: "Two Sum" + leetcode_url: "https://leetcode.com/problems/two-sum/" + difficulty: "easy" + tags: ["Arrays & Hashing"] + +solutions: + python: "problems/two_sum/two_sum.py" + cpp: "problems/two_sum/two_sum.cc" + +complexity: + time: "O(n)" + space: "O(n)" + +notes: "" +readme_link: "" diff --git a/problems/valid_palindrome/config.yml b/problems/valid_palindrome/config.yml new file mode 100644 index 0000000..4ea7a13 --- /dev/null +++ b/problems/valid_palindrome/config.yml @@ -0,0 +1,17 @@ +problem: + number: 125 + title: "Valid Palindrome" + leetcode_url: "https://leetcode.com/problems/valid-palindrome/" + difficulty: "easy" + tags: ["Two Pointers"] + +solutions: + python: "problems/valid_palindrome/valid_palindrome.py" + cpp: "problems/valid_palindrome/valid_palindrome.cc" + +complexity: + time: "O(n)" + space: "O(1)" + +notes: "" +readme_link: "" diff --git a/requirements.txt b/requirements.txt index 56d8c12..4ea4f71 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,6 @@ ruff # Testing tools pytest pytest-cov + +# YAML processing library +PyYAML diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py new file mode 100644 index 0000000..5d3fd01 --- /dev/null +++ b/scripts/generate_readme.py @@ -0,0 +1,313 @@ +#!/usr/bin/env python3 +""" +README Generator for LeetCode Solutions +Generates the problems table from individual problem configuration files. +""" + +import os +import yaml +import argparse +from pathlib import Path +from typing import Dict, List, Any +from collections import defaultdict + + +class Colors: + """ANSI color codes matching the Makefile color functions.""" + + BLUE = "\033[1;34m" + GREEN = "\033[1;32m" + YELLOW = "\033[1;33m" + RED = "\033[1;31m" + CYAN = "\033[1;36m" + RESET = "\033[0m" + + @staticmethod + def blue(text: str) -> str: + return f"{Colors.BLUE}{text}{Colors.RESET}" + + @staticmethod + def green(text: str) -> str: + return f"{Colors.GREEN}{text}{Colors.RESET}" + + @staticmethod + def yellow(text: str) -> str: + return f"{Colors.YELLOW}{text}{Colors.RESET}" + + @staticmethod + def red(text: str) -> str: + return f"{Colors.RED}{text}{Colors.RESET}" + + @staticmethod + def cyan(text: str) -> str: + return f"{Colors.CYAN}{text}{Colors.RESET}" + + +class ReadmeGenerator: + def __init__(self, root_dir: str = "."): + self.root_dir = Path(root_dir) + self.config_dir = self.root_dir / "config" + self.problems_dir = self.root_dir / "problems" + + def load_config(self, config_file: str) -> Dict[str, Any]: + """Load YAML configuration file.""" + config_path = self.config_dir / config_file + if not config_path.exists(): + return {} + + with open(config_path, "r") as f: + return yaml.safe_load(f) + + def find_problem_configs(self) -> List[Path]: + """Find all problem configuration files.""" + config_files = [] + for root, dirs, files in os.walk(self.problems_dir): + if "config.yml" in files: + config_files.append(Path(root) / "config.yml") + return config_files + + def load_problem_config(self, config_path: Path) -> Dict[str, Any]: + """Load a single problem configuration.""" + with open(config_path, "r") as f: + return yaml.safe_load(f) + + def validate_problem_config(self, config: Dict[str, Any]) -> bool: + """Validate problem configuration against allowed values.""" + difficulties = self.load_config("difficulties.yml").get("difficulties", []) + tags = self.load_config("tags.yml").get("tags", []) + + problem = config.get("problem", {}) + + # Validate difficulty + if problem.get("difficulty") not in difficulties: + print( + Colors.red( + f"✗ Invalid difficulty '{problem.get('difficulty')}' in problem {problem.get('number')}" + ) + ) + return False + + # Validate tags + problem_tags = problem.get("tags", []) + for tag in problem_tags: + if tag not in tags: + print( + Colors.red( + f"✗ Invalid tag '{tag}' in problem {problem.get('number')}" + ) + ) + return False + + return True + + def generate_anchor(self, tag: str) -> str: + """Generate a markdown anchor from a tag name.""" + return tag.lower().replace(" ", "-").replace("&", "") + + def format_solutions(self, solutions: Dict[str, str]) -> str: + """Format solution links for the table.""" + formatted_solutions = [] + for lang, path in solutions.items(): + lang_display = "C++" if lang == "cpp" else lang.capitalize() + formatted_solutions.append(f"[{lang_display}](./{path})") + return ", ".join(formatted_solutions) + + def generate_table_of_contents(self) -> str: + """Generate table of contents for algorithms section.""" + tags = self.load_config("tags.yml").get("tags", []) + toc_items = [] + + for tag in tags: + tag_anchor = self.generate_anchor(tag) + toc_items.append(f"- [{tag}](#{tag_anchor})") + + return "\n".join(toc_items) + + def generate_problems_table(self) -> str: + """Generate the problems table organized by tags.""" + config_files = self.find_problem_configs() + problems_by_tag = defaultdict(list) + + # Load and organize problems by tag + for config_path in config_files: + try: + config = self.load_problem_config(config_path) + if not self.validate_problem_config(config): + continue + + problem = config["problem"] + for tag in problem.get("tags", ["Uncategorized"]): + problems_by_tag[tag].append(config) + except Exception as e: + print(Colors.red(f"✗ Error loading {config_path}: {e}")) + continue + + # Generate markdown + markdown_sections = [] + + # Only include tags that have problems + available_tags = self.load_config("tags.yml").get("tags", []) + for tag in available_tags: + if tag not in problems_by_tag: + continue + + problems = sorted( + problems_by_tag[tag], key=lambda x: x["problem"]["number"] + ) + + # Create section header + tag_anchor = self.generate_anchor(tag) + markdown_sections.append(f"## {tag}") + markdown_sections.append("") + + # Create table header + table_header = ( + "| # | Title | Solution | Time | Space | Difficulty | Tag | Note |" + ) + table_divider = ( + "|---|-------|----------|------|-------|------------|-----|------|" + ) + markdown_sections.extend([table_header, table_divider]) + + # Add problem rows + for config in problems: + problem = config["problem"] + solutions = config.get("solutions", {}) + complexity = config.get("complexity", {}) + + # Format the row + number = problem["number"] + title = f"[{problem['title']}]({problem['leetcode_url']})" + solution_links = self.format_solutions(solutions) + time_complexity = f"_{complexity.get('time', 'N/A')}_" + space_complexity = f"_{complexity.get('space', 'N/A')}_" + difficulty = problem["difficulty"].capitalize() + tags_display = "" # Could show additional tags if needed + notes = config.get("notes", "") + + # Add readme link if available + if config.get("readme_link"): + if notes: + notes += f" [Details]({config['readme_link']})" + else: + notes = f"[Details]({config['readme_link']})" + + row = f"| {number} | {title} | {solution_links} | {time_complexity} | {space_complexity} | {difficulty} | {tags_display} | {notes} |" + markdown_sections.append(row) + + markdown_sections.append("") + + return "\n".join(markdown_sections) + + def update_readme(self, readme_path: str = "README.md"): + """Update the README file with generated problems table.""" + readme_file = self.root_dir / readme_path + + if not readme_file.exists(): + print(Colors.red(f"✗ README file {readme_file} not found!")) + return + + print("Generating README from problem configurations...") + + # Read current README + with open(readme_file, "r") as f: + content = f.read() + + # Generate new problems table + toc = self.generate_table_of_contents() + problems_table = self.generate_problems_table() + + # Find the algorithms section + start_marker = "## Algorithms" + + start_idx = content.find(start_marker) + if start_idx == -1: + print(Colors.red("✗ Could not find 'Algorithms' section in README")) + return + + # Look for the end of the algorithms content + # We need to find either: + # 1. The next top-level section that's NOT a tag section (## but not a tag name) + # 2. End of file if no such section exists + + available_tags = self.load_config("tags.yml").get("tags", []) + + # Start searching after the "## Algorithms" line + search_start = start_idx + len(start_marker) + + # Find all "## " occurrences after the algorithms section + end_idx = len(content) # Default to end of file + pos = search_start + + while True: + next_section = content.find("\n## ", pos) + if next_section == -1: + # No more sections found + break + + # Extract the section title (everything after "## " until newline) + section_start = next_section + 4 # Skip "\n## " + section_end = content.find("\n", section_start) + if section_end == -1: + section_title = content[section_start:].strip() + else: + section_title = content[section_start:section_end].strip() + + # Check if this section title is NOT one of our algorithm tags + if section_title not in available_tags: + # This is a non-algorithm section, so algorithms content ends here + end_idx = next_section + break + + # Continue searching after this section + pos = next_section + 1 + + # Preserve content after the algorithms section + content_after = content[end_idx:] if end_idx < len(content) else "" + + # Replace only the algorithms section + new_algorithms_section = f"## Algorithms\n\n{toc}\n\n{problems_table}" + + new_content = content[:start_idx] + new_algorithms_section + content_after + + # Write updated README + with open(readme_file, "w") as f: + f.write(new_content) + + # Show statistics + config_files = self.find_problem_configs() + valid_configs = 0 + for config_path in config_files: + try: + config = self.load_problem_config(config_path) + if self.validate_problem_config(config): + valid_configs += 1 + except (yaml.YAMLError, FileNotFoundError, Exception): + pass + + print(Colors.green("✓ README updated successfully!")) + print(Colors.green(f" Processed {valid_configs} valid problem configurations")) + + +def main(): + parser = argparse.ArgumentParser( + description="Generate README from problem configurations" + ) + parser.add_argument("--root", default=".", help="Root directory of the project") + parser.add_argument("--readme", default="README.md", help="README file path") + parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output") + + args = parser.parse_args() + + if args.verbose: + print(Colors.blue("=== LeetCode README Generator ===")) + print(Colors.yellow(f"Root directory: {args.root}")) + print(Colors.yellow(f"README file: {args.readme}")) + print("") + + generator = ReadmeGenerator(args.root) + generator.update_readme(args.readme) + + +if __name__ == "__main__": + main()