Skip to main content
  1. Posts/

Make LeetCode (MLC)

·4 mins
Table of Contents

Overview #

I have found that practicing LeetCode problems helps me stay sharp and use them as a way to get better at both general problem solving and Test Driven Development. One painpoint I have had is starting a new problem, since I want to store all my work in my own git repo in a specific format, and I want to be able to run my tests easily. It requires:

  • figuring out which folder to add the file to (easy, medium, hard)
  • creating the file with the correct naming convention, using the problem number and slug
  • copy/pasting the problem description and starter code snippet
  • importing that new file into my test file and scaffolding the unit test class, base test case, and first test to be filled out

All of this takes around five minutes, but the repetitive nature easily lends itself to automation – so I did it.

You can find the mlc.sh and sample .mlc config files here – feel free to use it and tweak it to your needs.

To set it up:

  • copy the .mlc file to your $HOME folder and edit the naming per your folder structure

  • add the mlc.sh file anywhere and add it to your either an already executable bin folder (like /usr/local/bin or add the folder to your PATH):

    cp mlc.sh /usr/local/bin/mlc
    chmod +x /usr/local/bin/mlc
    

    or

    mkdir ~/scripts
    cp mlc.sh ~/scripts/mlc
    chmod +x ~/scripts/mlc
    PATH=$PATH:~/scripts
    

To run it: mlc -u "URL_OF_PROBLEM", e.g.: mlc.sh -u "https://leetcode.com/problems/valid-palindrome"

Notes #

  • Decided to create it in bash because it is simple file creation from parsing a url. It could easily be turned into a Python or Golang CLI tool – maybe I’ll create those in the future.

  • It is tightly coupled with my current folder structure and practice language of choice / tooling:

    • Language = python3

    • Tooling = in-built unittest module for testing

    • Folder Structure:

      .
      ├── README.md
      ├── lc/                 # configurable by editing the lc_folder variable
      │   ├── 150/            # configurable by editing the study_plan variable
      │   │   ├── 1_easy
      │   │   ├── 2_medium
      │   │   └── 3_hard
      ├── scripts/
      │   └── mlc.sh
      ├── tests/              # configurable by editing the lc_test_folder variable
      │   ├── data/
      │   ├── test_lc.py
      
  • It is very customized to the way I format solution files and test cases:

    • Solution Files:

      • stored in study plan folder, by difficulty
      • naming convention: p####_slug_of_problem.py
      • file header:
        • file name
        • problem title
        • problem url
        • problem description
        • snippet of provided starter python3 solution code
        # 0125_valid_palindrome.py
        #
        # Valid Palindrome
        #
        # https://leetcode.com/problems/valid-palindrome
        # A phrase is a palindrome if,
        # after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters,
        # it reads the same forward and backward
        # Alphanumeric characters include letters and numbers
        #
        # Given a string s,
        # return true if it is a palindrome,
        # or false otherwise
        #
      
      
        class Solution:
            def isPalindrome(self, s: str) -> bool:
      
    • Test File:

      • singular test file with tests for all problems

      • requires importing each file separately because of the folder structure, so need to have a sys.path.append for the location of each of the solution folders

      • uses unittest

      • uses a base_test which does a call to the function being created and compares the expected value and actual results

      • creates a scaffolded test_1 which contains placeholders for each argument, as well as the expected value, and uses the base_test

      • top of test_lc.py file:

      import sys
      import unittest
      
      sys.path.insert(0, "./lc")
      sys.path.append("./lc/150/1_easy")
      sys.path.append("./lc/150/2_medium")
      sys.path.append("./lc/150/3_hard")
      sys.path.append("./tests/data")
      
      if __name__ == "__main__":
          unittest.main()
      
      • bottom of test_lc.py file:
      import p0125_valid_palindrome
      class ValidPalindromeTest(unittest.TestCase):
          def base_test(self, s, expected):
              unit_test = p0125_valid_palindrome.Solution()
              got = unit_test.isPalindrome(s)
              self.assertEqual(got, expected)
      
          def test_1(self):
              s, expected = 0, 0
              self.base_test(s, expected)
              pass
      
  • The most interesting part of this tool is that I got a chance to play with LeetCode’s GraphQL setup, and was able to tweak the input query to get the exact output that I wanted. I didn’t search for any documentation on using their system – just looked at the network requests that showed up while loading a problem. I was expected typical REST requests and was surprised to see them using GraphQL.

  • I have tested this extensively for python3 using unittest on MacOs, not Windows or Linux. I expect you should be able to easily run this using WSL or on Linux – it is plain bash, nothing fancy.

TODOs (maybe) #

  • Externalize the configuration - DONE in v0.0.2
  • Create a cross-platform port of this in Golang which would be easier to download and run.
  • Extend to support pytest
  • Extend to support other languages (starting with Java, Go, Javascript, and Rust)

If you have found this useful, ran into bugs or issues using it, or if you are interested in having some other features or enhancements, drop a comment either here or in the mlc.sh Gist.