Skip to main content

leezy: leetcode helper for the lazy

Project description

给Python的leetcode本地刷题小工具

Quick Start

Install

Requirements:

  • Python >= 3.6
  • requests >= 2.18.0
  • pytest >= 5.1.3

在终端执行:

$ pip install leezy

Examples

  1. 拉取题目

在终端进入刷题目录:

$ leezy pull 1

在当前目录生成如下目录和文件

$ 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. 运行/查看结果
$ python "001 - Two Sum\001_two-sum.py"
+----------+----------+---------------+---------------+
|          |  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个

$ python "001 - Two Sum\001_two-sum.py"
+----------+----------+-----------+
|          |  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()

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]完成拉取题目及设置相关操作

$ leezy -h
usage: leezy [-h] COMMAND [...]

optional arguments:
  -h, --help  show this help message and exit

commands:
  use 'leezy command -h' to see more

    pull      拉取题目到本地文件
    show      打印编号的题目
    config    全局配置

其中config支持git风格的属性配置

usage: leezy config [-h] [--add | --unset | --list]

optional arguments:
  -h, --help  show this help message and exit
  --add       name value
  --unset     name
  --list

目前支持使用config设置solution结果的表格设置, example:

$ leezy config --add table.max_col_width 50

$ leezy config --add table.max_content_length -1

$ leezy config --unset table

可用配置项:

name description default
table.max_col_width 表格列的最大宽度 40字符
table.max_content_length 每个单元格支持的最长内容长度,超过部分将被截断(-1表示不截断) 100字符

辅助类

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

leezy.assists中导入

from leezy.assists import TreeNode, LinkedListNode

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 = LinkedListNode.make_linked_list([1, 2, 3, 4, 5])
print(type(l)) # <class 'leezy.assists.LinkedListNode'>
print(l)       # 1->2->3->4->5
print(l.next)  # 2->3->4->5

现在支持的类型:

  • TreeNode
  • LinkedListNode

除了手动使用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.3.1.tar.gz (19.2 kB view hashes)

Uploaded Source

Built Distribution

leezy-0.3.1-py3-none-any.whl (22.3 kB view hashes)

Uploaded Python 3

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