Skip to main content

leezy: leetcode helper for the lazy

Project description

Leezy PyPI - Python Version PyPI

给Python的LeetCode刷题工具,在本地管理你的一题多解🍖🍗🥩

Install

在终端执行:

$ pip install leezy

Examples

  1. 设置工作目录
$ leezy config --add core.workdir <DIR>

例如leezy config --add core.workdir D:\leetcode

  1. 拉取题目
$ leezy pull 1

workdir下生成如下目录和文件

$ tree
.
└── 001 - Two Sum
    ├── 001.html # 题目描述,在浏览器或者其他html预览器中查看
    └── 001_two-sum.py # solution模板,在这里编辑解法
# 001_two-sum.py(initial)
from leezy import Solution, solution


class Q001(Solution):  # 继承Solution
    @solution    # 被solution装饰的函数将参与最后的结果输出或测试
    def twoSum(self, nums, target):
        pass


def main():
    q = Q001()
    q.add_case(q.case([2, 7, 11, 15], 9)) # 添加自己的测试用例
    q.run()


if __name__ == "__main__":
    main()
  1. 尝试死磕多种解法
# 001_two-sum.py(modified)
from leezy import Solution, solution


class Q001(Solution):
    @solution
    def twoSum(self, nums, target):
        for i,x in enumerate(nums):
            for j, y in enumerate(nums[i+1:], i+1):
                if x + y == target:
                    return [i, j]

    @solution
    def twoSum_sort(self, nums, target):
        L, i, j = len(nums), 0, len(nums)-1
        sorted_i = sorted(range(L), key=nums.__getitem__)
        while i < j:
            s = nums[sorted_i[i]] + nums[sorted_i[j]]
            if s > target:
                j -= 1
            elif s < target:
                i += 1
            else:
                return [sorted_i[i], sorted_i[j]]

    @solution
    def twoSum_hash(self, nums, target):
        hash_table = {}
        for i, x in enumerate(nums):
            another = target - x
            if x in hash_table:
                return [hash_table[x], i]
            else:
                hash_table[another] = i


def main():
    q = Q001()
    q.add_case(q.case([3, 2, 4], 6))
    q.add_case(q.case([3,3], 6))
    q.add_case(q.case([2, 7, 11, 15], 9))
    q.add_case(q.case([2, 7, 11, 15], 17))
    q.add_case(q.case([2, 7, 11, 15], 26))
    q.run()


if __name__ == "__main__":
    main()
  1. 运行/查看结果
$ leezy run 1
+----------+----------+---------------+---------------+
|          |  twoSum  |  twoSum_sort  |  twoSum_hash  |
+==========+==========+===============+===============+
|  case 0  |  [1, 2]  |  [1, 2]       |  [1, 2]       |
+----------+----------+---------------+---------------+
|  case 1  |  [0, 1]  |  [0, 1]       |  [0, 1]       |
+----------+----------+---------------+---------------+
|  case 2  |  [0, 1]  |  [0, 1]       |  [0, 1]       |
+----------+----------+---------------+---------------+
|  case 3  |  [0, 3]  |  [0, 3]       |  [0, 3]       |
+----------+----------+---------------+---------------+
|  case 4  |  [2, 3]  |  [2, 3]       |  [2, 3]       |
+----------+----------+---------------+---------------+
  1. 执行测试

在添加测试用例时,可以使用assert_equal添加期望的输出,这类测试用例将自动生成测试代码。

# 001_two-sum.py(modified, testcase-added)

...

def main():
    q = Q001()
    q.add_case(q.case([3, 2, 4], 6))
    q.add_case(q.case([3,3], 6))
    q.add_case(q.case([2, 7, 11, 15], 9).assert_equal([0, 1]))
    q.add_case(q.case([2, 7, 11, 15], 17).assert_equal([0, 3]))
    q.add_case(q.case([2, 7, 11, 15], 26).assert_equal([2, 3]))
    q.run()

运行后,为3个 solution 各自运行3个测试,总共通过9个

$ leezy run 1
+----------+----------+-----------+
|          |  twoSum  |  two_sum  |
+==========+==========+===========+
|  case 0  |  [1, 2]  |  [1, 2]   |
+----------+----------+-----------+
|  case 1  |  [0, 1]  |  [0, 1]   |
+----------+----------+-----------+
.........                                                                   [100%]
9 passed in 0.09s

此外,测试用例支持assert_true_with(fn),传入自定义测试函数。比如第1054题,要求结果数组相邻的两个数不相等,因此可以构建如下的测试函数

from itertools import chain
from collections import Counter


class Q1054(Solution):
    @solution
    def rearrangeBarcodes(self, barcodes):
        # 452ms 92.03%
        N = len(barcodes)
        idx = chain(range(0, N, 2), range(1, N, 2))
        counter = Counter(barcodes)
        ans = [0] * N
        for x, cnt in counter.most_common():
            for _ in range(cnt):
                ans[next(idx)] = x
        return ans


def main():
    q = Q1054()

    def check(A):
        return all(x != nx for x, nx in zip(A, A[1:])

    q.add_case(q.case([1, 1, 1, 2, 2, 2]).assert_true_with(check))
    q.add_case(q.case([1, 2, 2, 2, 5]).assert_true_with(check))
    q.add_case(q.case([1, 1, 1, 1, 2, 2, 3, 3]).assert_true_with(check))
    q.run()
  1. 提交解法

提交第一题的第三个解法

$ leezy submit 3@1
Is it OK to submit function 'twoSum'?

class Solution:
    def twoSum(self, nums, target):  
        hash_table = {}
        for i, x in enumerate(nums): 
            another = target - x
            if x in hash_table:
                return [hash_table[x], i]
            else:
                hash_table[another] = i

> [Yes/No]? y
----------------Accepted!----------------
  time used & rank: 40 ms faster than 93.07%
memory used & rank: 14.9 MB less than 6.25%

more helpful links:
    https://leetcode-cn.com/submissions/detail/55171676
    https://leetcode.com/problems/two-sum/discuss/

Why leezy?

leezy名字来自于leetcode和lazy的组合。懒惰就是生产力。

如果你有以下标签所描述的倾向,leezy可能会给你一些参考:

【第一遍刷Leetcode】【使用本地编辑器】【愿意尝试一题多解】【少些重复print、测试用例】

还可以通过下面的问题进一步了解为什么要使用leezy

  • 为什么不在线刷题?

    首先,因为是第一次做题,希望把重点放在解题本身,环境就使用自己习惯的就好。

    其次,在线run code的速度不稳定,不适合初期的debug。

    最后,在本地记录解法,管理起来更直接,离线也可以随时搜索复习。

    如果是第n遍刷题了,直接上web更方便。

  • leezy的核心是什么?

    少写print,少写重复测试用例。和上面提到的标签所暗示的那样,做题大概率不能一次成功,需要在本地用自己的测试用例反复运行,打印结果,修改。当使用多个解法时,又需要重复这些工作。所以一次性写完这些重复的print、测试用例就是leezy最平常且简单的目的

  • 和其他刷题工具有什么区别?

    其他的刷题工具,典型的有基于CLI的leetcode-cli, 基于VSCode的leetcode for vscode(也基于leetcode-cli),都支持完整的刷题流程:用户登录、题目拉取、编写、测试、提交、查看统计数据。本质是把网页版的功能在用另一套接口进行实现。

    leezy虽然也可以登录、拉取、测试以及提交,但相比上述工具,leezy对题目拉取后,模板文件不再和网页上提供的模板一致,更方便实现一题多解的本地调试

More things

命令行

使用leezy [command]完成拉取题目及设置相关操作

usage: leezy [options] COMMAND

Manage your Python solutions better

optional arguments:
  -h, --help     show this help message and exit
  -V, --version  show program's version number and exit
  --zone ZONE    'cn' or 'us', default is 'cn'
  --dir DIR      assign a temporary workdir for this session
  -v             verbose, use multiple -vv... to show more log

COMMANDS:
  use 'leezy <COMMAND> -h' to see more

  -⭐-
    show         show basic info of problems
    pull         pull problems to local files
    run          run your solutions, see outputs or test them
    submit       submit your solution to leetcode
    plot         show a heatmap of your all accepted solutions
    config       manage global configs

其中config支持git风格的属性配置,目前的可配置项为:

name description default
table.max_col_width 表格列的最大宽度 40字符
table.max_content_length 每个单元格支持的最长内容长度,超过部分将被截断(-1表示不截断) 100字符
core.workdir 刷题目录,每次pull、run都将基础该目录 当前目录
core.zone 刷题网站版本,中国区还是美区 cn
log.level 日志等级 warning

辅助类

针对使用链表或者树结构的题目,也提供了和网页版类似的基础类型,初始化的参数也和网页版保持一致。

leezy.assists中导入

from leezy.assists import TreeNode, ListNode

t = TreeNode.make_tree([1, 2, 3, 4, 5, None, 6])
print(type(t)) # <class 'leezy.assists.TreeNode'>
print(t)       # Tree(1-2-3-4-5-None-6)
print(t.left)  # Tree(2-4-5)
print(t.right) # Tree(3-None-6)


l = ListNode.make_linked_list([1, 2, 3, 4, 5])
print(type(l)) # <class 'leezy.assists.ListNode'>
print(l)       # 1->2->3->4->5
print(l.next)  # 2->3->4->5

现在支持的类型:

  • TreeNode
  • ListNode

除了手动使用make_tree, make_linkedlist构造,还提供了TreeContext,LinkedListContext,将add_case传入的集合类型参数自动构造为树或链表。省得每次添加测试用例都要写make_*函数

from leezy import Solution, solution
from leezy.assists import TreeContext # 导入TreeContext


class Q700(Solution):
    @solution
    def searchBST(self, root, val):
        if root is None:
            return
        if root.val > val:
            return self.searchBST(root.left, val)
        elif root.val < val:
            return self.searchBST(root.right, val)
        else:
            return root

    @solution
    def search(self, root, val):
        while root:
            if root.val > val:
                root = root.left
            elif root.val < val:
                root = root.right
            else:
                return root
        return None


def main():
    q = Q700()
    q.set_context(TreeContext)  # 设置TreeContex
    q.add_case(q.case([4, 2, 7, 1, 3], 2)) # 这里传入的列表自动会被转化为Tree
    q.run()

为了进一步简化,pull命令支持--context选项

$ leezy pull --context tree 700 701

这样700、701题的源文件自动添加好TreeContext


更多功能和限制说明,待更新

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

leezy-0.5.3.tar.gz (34.2 kB view details)

Uploaded Source

Built Distribution

leezy-0.5.3-py3-none-any.whl (32.6 kB view details)

Uploaded Python 3

File details

Details for the file leezy-0.5.3.tar.gz.

File metadata

  • Download URL: leezy-0.5.3.tar.gz
  • Upload date:
  • Size: 34.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/40.6.2 requests-toolbelt/0.9.1 tqdm/4.45.0 CPython/3.6.10

File hashes

Hashes for leezy-0.5.3.tar.gz
Algorithm Hash digest
SHA256 deecf6d75300e34a52311b98ebcc7609b4aef8be5e835dc9991ced701c755156
MD5 33d484650a700f179468e606be20fd9d
BLAKE2b-256 3473dab0736ac91187656816ce7efe2b0e52ad9651d92c59834d5baf96d53aa3

See more details on using hashes here.

File details

Details for the file leezy-0.5.3-py3-none-any.whl.

File metadata

  • Download URL: leezy-0.5.3-py3-none-any.whl
  • Upload date:
  • Size: 32.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/40.6.2 requests-toolbelt/0.9.1 tqdm/4.45.0 CPython/3.6.10

File hashes

Hashes for leezy-0.5.3-py3-none-any.whl
Algorithm Hash digest
SHA256 93864411f0c373419b4455a1dd35d23bf83db3aba1e5411acf6293a11c3e3504
MD5 271c8a38070347d05b0aefe09aa71e23
BLAKE2b-256 f05eed02a13aec29a55b142ed5744a7e022c606c3329ca850ef03aabe8048074

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page