爬取Leetcode Hot 100 题单

最近在刷leetcode hot 100,想做一个记录,方便后面来复习不太熟练的题目,于是想通过python来爬取 leetcode hot 100 的题单,格式为 "- 1 两数之和、[两数之和](两数之和链接)"

借助Claude 编写代码,爬取成功,以下是程序代码:

复制代码
"""
LeetCode Hot 100 题目爬虫
这个程序可以自动爬取 LeetCode 热门 100 题的题目列表
并保存为文本、CSV 和 JSON 三种格式

功能:绕过 Cloudflare 防护,自动爬取题目信息
"""

# ==================== 导入需要的库 ====================
# undetected_chromedriver: 可以绕过网站反爬虫检测的浏览器驱动
import undetected_chromedriver as uc
# selenium 的相关模块,用于自动化控制浏览器
from selenium.webdriver.common.by import By  # 用于定位网页元素
from selenium.webdriver.support.ui import WebDriverWait  # 用于等待页面加载
from selenium.webdriver.support import expected_conditions as EC  # 用于判断元素是否加载完成
# 其他标准库
import time  # 用于添加等待时间
import csv  # 用于保存 CSV 格式文件
import json  # 用于保存 JSON 格式文件
import re  # 用于正则表达式匹配(提取题号和标题)


def crawl_leetcode_hot100():
    """
    主要爬取函数 - 自动模式

    这个函数会:
    1. 自动打开浏览器
    2. 访问 LeetCode Hot 100 页面
    3. 等待 Cloudflare 验证通过
    4. 滚动页面加载所有题目
    5. 提取题目信息(编号、标题、链接)
    6. 保存为三种格式的文件

    返回值:题目列表(list),每个元素是一个字典,包含 id、title、url
    """

    # ==================== 第一步:配置浏览器 ====================
    # 创建浏览器配置选项
    options = uc.ChromeOptions()

    # 可选:无头模式(不显示浏览器窗口,取消注释下一行可启用)
    # options.add_argument('--headless')

    # 禁用自动化控制特征,让网站更难检测到我们是机器人
    options.add_argument('--disable-blink-features=AutomationControlled')

    print("正在初始化浏览器...")
    # 创建浏览器实例(使用 undetected_chromedriver 来绕过反爬虫)
    driver = uc.Chrome(options=options)

    try:
        # ==================== 第二步:访问目标网页 ====================
        # LeetCode Hot 100 的页面地址
        url = 'https://leetcode.cn/problem-list/2cktkvj/'
        print(f"正在访问: {url}")
        # 让浏览器打开这个网页
        driver.get(url)

        # ==================== 第三步:等待 Cloudflare 验证 ====================
        print("等待页面加载(可能需要通过Cloudflare验证)...")
        # 等待 10 秒,让页面有时间加载和通过验证
        time.sleep(10)

        # 检查页面源代码中是否还有 Cloudflare 的验证提示
        if "cloudflare" in driver.page_source.lower() or "请稍候" in driver.page_source:
            print("检测到Cloudflare防护,等待验证完成...")
            # 如果还在验证,再多等 15 秒
            time.sleep(15)

        # ==================== 第四步:滚动页面加载所有内容 ====================
        print("滚动页面加载内容...")
        # 获取当前页面的高度
        last_height = driver.execute_script("return document.body.scrollHeight")
        scroll_attempts = 0  # 记录已经滚动了多少次
        max_scrolls = 10  # 最多滚动 10 次

        # 循环滚动页面,直到没有新内容加载或达到最大次数
        while scroll_attempts < max_scrolls:
            # 滚动到页面底部(这会触发加载更多内容)
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            # 等待 2 秒让新内容加载
            time.sleep(2)
            # 获取滚动后的新页面高度
            new_height = driver.execute_script("return document.body.scrollHeight")

            # 如果页面高度没有变化,说明已经加载完所有内容
            if new_height == last_height:
                break

            # 更新页面高度,继续下一次滚动
            last_height = new_height
            scroll_attempts += 1
            print(f"滚动进度: {scroll_attempts}/{max_scrolls}")

        # ==================== 第五步:查找题目元素 ====================
        # 创建一个等待对象,最多等待 20 秒
        wait = WebDriverWait(driver, 20)
        elements = []  # 用于存储找到的题目元素

        # 定义多个可能的选择器(因为网页结构可能变化)
        # XPath 是一种定位网页元素的语言
        selectors = [
            "//a[contains(@href, '/problems/')]",  # 查找所有包含 /problems/ 的链接
            "//div[@role='row']//a",  # 查找表格行中的链接
            "//table//a[contains(@href, '/problems/')]",  # 查找表格中的题目链接
            "//div[contains(@class, 'question')]//a",  # 查找问题类元素中的链接
        ]

        # 尝试每一个选择器,直到找到元素
        for selector in selectors:
            try:
                print(f"尝试选择器: {selector}")
                # 使用当前选择器查找元素
                found_elements = driver.find_elements(By.XPATH, selector)

                # 如果找到了元素,就不再尝试其他选择器
                if found_elements:
                    elements = found_elements
                    print(f"✓ 找到 {len(elements)} 个元素")
                    break
            except Exception as e:
                # 如果这个选择器失败了,继续尝试下一个
                print(f"✗ 选择器失败: {e}")
                continue

        # 如果所有选择器都没找到元素
        if not elements:
            print("\n⚠️ 未找到题目元素,保存页面源代码用于调试...")
            # 保存页面源代码,方便我们分析问题
            with open('debug_page.html', 'w', encoding='utf-8') as f:
                f.write(driver.page_source)
            print("页面已保存到 debug_page.html")
            return []  # 返回空列表

        # ==================== 第六步:提取题目信息 ====================
        problems = []  # 用于存储所有题目信息的列表
        seen_urls = set()  # 用于去重(set 不允许重复元素)

        print("\n开始提取题目信息...")
        # 遍历每一个找到的元素
        for element in elements:
            try:
                # 获取链接地址
                href = element.get_attribute('href')

                # 过滤掉不符合要求的链接:
                # 1. href 为空
                # 2. 不包含 /problems/
                # 3. 已经处理过(去重)
                if not href or '/problems/' not in href or href in seen_urls:
                    continue

                # 将这个链接加入已处理集合
                seen_urls.add(href)

                # 获取元素的文本内容(题目标题)
                text = element.text.strip()  # strip() 去掉首尾空格

                # 如果文本为空,跳过这个元素
                if not text:
                    continue

                # ==================== 解析题目编号和标题 ====================
                # LeetCode 的题目文本通常是:
                # "160. 相交链表\n67.9%\n简单"
                # 我们只需要第一行的 "160. 相交链表"

                # split('\n') 按换行符分割,[0] 取第一行
                text = text.split('\n')[0]

                # 初始化题号和标题
                problem_id = ""  # 题目编号(如 "160")
                problem_title = text  # 题目标题(如 "相交链表")

                # 使用正则表达式匹配 "数字. 标题" 的格式
                # r'^(\d+)\.\s*(.+)$' 的含义:
                # ^ : 从字符串开头开始匹配
                # (\d+) : 匹配一个或多个数字,并捕获(括号表示捕获组)
                # \. : 匹配一个点号(. 在正则中有特殊含义,需要转义)
                # \s* : 匹配零个或多个空白字符
                # (.+) : 匹配一个或多个任意字符,并捕获
                # $ : 匹配到字符串末尾
                match = re.match(r'^(\d+)\.\s*(.+)$', text)

                if match:
                    # 如果匹配成功,提取题号和标题
                    problem_id = match.group(1)  # 第一个捕获组:题号
                    problem_title = match.group(2).strip()  # 第二个捕获组:标题
                else:
                    # 如果没有匹配到标准格式,尝试从文本开头提取数字
                    id_match = re.match(r'^(\d+)', text)
                    if id_match:
                        problem_id = id_match.group(1)
                        # 移除题号和点号,得到标题
                        # len(problem_id) 是题号的长度
                        # lstrip('. ') 移除左边的点号和空格
                        problem_title = text[len(problem_id):].lstrip('. ')

                # 将题目信息存储为字典
                problems.append({
                    'id': problem_id,  # 题目编号
                    'title': problem_title,  # 题目标题
                    'url': href  # 题目链接
                })

                # 在控制台显示进度
                print(f"已爬取: [{problem_id}] {problem_title}")

            except Exception as e:
                # 如果提取某个元素失败,打印错误但继续处理下一个
                print(f"提取元素失败: {e}")
                continue

        print(f"\n总共爬取到 {len(problems)} 道题目")

        # ==================== 第七步:保存数据到文件 ====================
        if problems:  # 如果有题目数据
            # --- 保存为纯文本格式(Markdown)---
            txt_filename = 'leetcode_hot100.txt'
            with open(txt_filename, 'w', encoding='utf-8') as f:
                # 遍历每道题目
                for p in problems:
                    # 生成 Markdown 格式的文本
                    # 格式:- 1 两数之和、[两数之和](链接)
                    if p['id']:  # 如果有题号
                        line = f"- {p['id']} {p['title']}、[{p['title']}]({p['url']})\n"
                    else:  # 如果没有题号
                        line = f"- {p['title']}、[{p['title']}]({p['url']})\n"
                    # 写入文件
                    f.write(line)
            print(f"✓ 已保存到 {txt_filename}")

            # --- 保存为 CSV 格式(表格)---
            csv_filename = 'leetcode_hot100.csv'
            with open(csv_filename, 'w', newline='', encoding='utf-8-sig') as f:
                # 创建 CSV 写入器,指定列名
                writer = csv.DictWriter(f, fieldnames=['id', 'title', 'url'])
                writer.writeheader()  # 写入表头
                writer.writerows(problems)  # 写入所有数据行
            print(f"✓ 已保存到 {csv_filename}")

            # --- 保存为 JSON 格式 ---
            json_filename = 'leetcode_hot100.json'
            with open(json_filename, 'w', encoding='utf-8') as f:
                # ensure_ascii=False 保证中文正常显示
                # indent=2 格式化输出,每一层缩进 2 个空格
                json.dump(problems, f, ensure_ascii=False, indent=2)
            print(f"✓ 已保存到 {json_filename}")

        return problems  # 返回题目列表

    except Exception as e:
        # ==================== 错误处理 ====================
        print(f"\n❌ 发生错误: {str(e)}")
        # 打印详细的错误堆栈信息
        import traceback
        traceback.print_exc()

        # 保存出错时的页面源代码,方便调试
        try:
            with open('error_page.html', 'w', encoding='utf-8') as f:
                f.write(driver.page_source)
            print("错误页面已保存到 error_page.html")
        except:
            pass

        return []  # 返回空列表

    finally:
        # ==================== 清理工作 ====================
        # finally 块中的代码无论是否发生错误都会执行
        print("\n关闭浏览器...")
        driver.quit()  # 关闭浏览器,释放资源


def crawl_with_manual_login():
    """
    手动登录版本

    这个函数会:
    1. 打开浏览器
    2. 暂停程序,让用户手动完成验证和登录
    3. 用户确认后继续爬取

    适用场景:
    - 自动模式失败时使用
    - 需要登录账号才能访问的页面
    """

    # 创建浏览器实例
    options = uc.ChromeOptions()
    driver = uc.Chrome(options=options)

    try:
        # 访问目标页面
        url = 'https://leetcode.cn/problem-list/2cktkvj/'
        print(f"正在访问: {url}")
        driver.get(url)

        # 显示操作提示
        print("\n" + "="*60)
        print("请在浏览器中完成以下操作:")
        print("1. 等待Cloudflare验证通过")
        print("2. 如需要,请手动登录LeetCode账号")
        print("3. 确保页面完全加载后,在控制台输入 'y' 继续")
        print("="*60 + "\n")

        # 等待用户确认
        response = input("准备好了吗?输入 'y' 继续: ")
        if response.lower() != 'y':
            print("操作已取消")
            return []

        # 滚动页面加载内容
        print("滚动页面...")
        for i in range(5):  # 滚动 5 次
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            time.sleep(2)  # 每次滚动后等待 2 秒

        # 查找所有题目链接
        elements = driver.find_elements(By.XPATH, "//a[contains(@href, '/problems/')]")

        problems = []  # 存储题目信息
        seen_urls = set()  # 用于去重

        # 遍历所有链接元素
        for element in elements:
            href = element.get_attribute('href')
            # 过滤无效链接和重复链接
            if not href or '/problems/' not in href or href in seen_urls:
                continue

            seen_urls.add(href)
            text = element.text.strip()

            if text:
                # 清理文本:只取第一行,去除通过率和难度
                text = text.split('\n')[0]

                problem_id = ""
                problem_title = text

                # 尝试匹配 "数字. 标题" 格式
                match = re.match(r'^(\d+)\.\s*(.+)$', text)
                if match:
                    problem_id = match.group(1)
                    problem_title = match.group(2).strip()
                else:
                    # 尝试提取数字开头
                    id_match = re.match(r'^(\d+)', text)
                    if id_match:
                        problem_id = id_match.group(1)
                        problem_title = text[len(problem_id):].lstrip('. ')

                problems.append({
                    'id': problem_id,
                    'title': problem_title,
                    'url': href
                })
                print(f"已爬取: [{problem_id}] {problem_title}")

        # 保存结果到文件
        if problems:
            # 保存为文本格式
            with open('leetcode_hot100.txt', 'w', encoding='utf-8') as f:
                for p in problems:
                    if p['id']:
                        line = f"- {p['id']} {p['title']}、[{p['title']}]({p['url']})\n"
                    else:
                        line = f"- {p['title']}、[{p['title']}]({p['url']})\n"
                    f.write(line)

            # 保存为 CSV 格式
            with open('leetcode_hot100.csv', 'w', newline='', encoding='utf-8-sig') as f:
                writer = csv.DictWriter(f, fieldnames=['id', 'title', 'url'])
                writer.writeheader()
                writer.writerows(problems)

            # 保存为 JSON 格式
            with open('leetcode_hot100.json', 'w', encoding='utf-8') as f:
                json.dump(problems, f, ensure_ascii=False, indent=2)

            print(f"\n✓ 成功爬取 {len(problems)} 道题目")
            print("✓ 已保存到 leetcode_hot100.txt")
            print("✓ 已保存到 leetcode_hot100.csv")
            print("✓ 已保存到 leetcode_hot100.json")

        return problems

    finally:
        # 关闭浏览器
        driver.quit()


# ==================== 程序入口 ====================
if __name__ == '__main__':
    """
    这是程序的主入口
    当直接运行这个 Python 文件时,会执行这里的代码
    """

    print("LeetCode Hot 100 爬虫")
    print("="*60)
    print("请选择模式:")
    print("1. 自动模式(推荐,使用undetected-chromedriver)")
    print("2. 手动模式(打开浏览器后暂停,让你手动登录)")
    print("="*60)

    # 获取用户输入
    choice = input("请输入选择 (1/2): ").strip()

    # 根据用户选择执行不同的函数
    if choice == '2':
        print("\n使用手动模式...")
        problems = crawl_with_manual_login()
    else:
        print("\n使用自动模式...")
        problems = crawl_leetcode_hot100()

    # 显示爬取结果
    if problems:
        print("\n" + "="*60)
        print(f"✓ 爬取完成!共获取 {len(problems)} 道题目")
        print("\n前10道题目预览:")
        # 显示前 10 道题目
        for i, p in enumerate(problems[:10], 1):
            print(f"{i}. [{p['id']}] {p['title']}")
            print(f"   {p['url']}")
    else:
        print("\n❌ 爬取失败,请检查网络或尝试手动模式")

需要安装相对应的库。

运行结果,leetcode hot 100 题单:

复制代码
- 160 相交链表、[相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists?envType=problem-list-v2&envId=2cktkvj)
- 236 二叉树的最近公共祖先、[二叉树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree?envType=problem-list-v2&envId=2cktkvj)
- 234 回文链表、[回文链表](https://leetcode.cn/problems/palindrome-linked-list?envType=problem-list-v2&envId=2cktkvj)
- 739 每日温度、[每日温度](https://leetcode.cn/problems/daily-temperatures?envType=problem-list-v2&envId=2cktkvj)
- 226 翻转二叉树、[翻转二叉树](https://leetcode.cn/problems/invert-binary-tree?envType=problem-list-v2&envId=2cktkvj)
- 221 最大正方形、[最大正方形](https://leetcode.cn/problems/maximal-square?envType=problem-list-v2&envId=2cktkvj)
- 215 数组中的第K个最大元素、[数组中的第K个最大元素](https://leetcode.cn/problems/kth-largest-element-in-an-array?envType=problem-list-v2&envId=2cktkvj)
- 208 实现 Trie (前缀树)、[实现 Trie (前缀树)](https://leetcode.cn/problems/implement-trie-prefix-tree?envType=problem-list-v2&envId=2cktkvj)
- 207 课程表、[课程表](https://leetcode.cn/problems/course-schedule?envType=problem-list-v2&envId=2cktkvj)
- 206 反转链表、[反转链表](https://leetcode.cn/problems/reverse-linked-list?envType=problem-list-v2&envId=2cktkvj)
- 200 岛屿数量、[岛屿数量](https://leetcode.cn/problems/number-of-islands?envType=problem-list-v2&envId=2cktkvj)
- 198 打家劫舍、[打家劫舍](https://leetcode.cn/problems/house-robber?envType=problem-list-v2&envId=2cktkvj)
- 169 多数元素、[多数元素](https://leetcode.cn/problems/majority-element?envType=problem-list-v2&envId=2cktkvj)
- 238 除自身以外数组的乘积、[除自身以外数组的乘积](https://leetcode.cn/problems/product-of-array-except-self?envType=problem-list-v2&envId=2cktkvj)
- 155 最小栈、[最小栈](https://leetcode.cn/problems/min-stack?envType=problem-list-v2&envId=2cktkvj)
- 152 乘积最大子数组、[乘积最大子数组](https://leetcode.cn/problems/maximum-product-subarray?envType=problem-list-v2&envId=2cktkvj)
- 148 排序链表、[排序链表](https://leetcode.cn/problems/sort-list?envType=problem-list-v2&envId=2cktkvj)
- 146 LRU 缓存、[LRU 缓存](https://leetcode.cn/problems/lru-cache?envType=problem-list-v2&envId=2cktkvj)
- 142 环形链表 II、[环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii?envType=problem-list-v2&envId=2cktkvj)
- 141 环形链表、[环形链表](https://leetcode.cn/problems/linked-list-cycle?envType=problem-list-v2&envId=2cktkvj)
- 139 单词拆分、[单词拆分](https://leetcode.cn/problems/word-break?envType=problem-list-v2&envId=2cktkvj)
- 136 只出现一次的数字、[只出现一次的数字](https://leetcode.cn/problems/single-number?envType=problem-list-v2&envId=2cktkvj)
- 647 回文子串、[回文子串](https://leetcode.cn/problems/palindromic-substrings?envType=problem-list-v2&envId=2cktkvj)
- 128 最长连续序列、[最长连续序列](https://leetcode.cn/problems/longest-consecutive-sequence?envType=problem-list-v2&envId=2cktkvj)
- 124 二叉树中的最大路径和、[二叉树中的最大路径和](https://leetcode.cn/problems/binary-tree-maximum-path-sum?envType=problem-list-v2&envId=2cktkvj)
- 322 零钱兑换、[零钱兑换](https://leetcode.cn/problems/coin-change?envType=problem-list-v2&envId=2cktkvj)
- 494 目标和、[目标和](https://leetcode.cn/problems/target-sum?envType=problem-list-v2&envId=2cktkvj)
- 461 汉明距离、[汉明距离](https://leetcode.cn/problems/hamming-distance?envType=problem-list-v2&envId=2cktkvj)
- 448 找到所有数组中消失的数字、[找到所有数组中消失的数字](https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array?envType=problem-list-v2&envId=2cktkvj)
- 438 找到字符串中所有字母异位词、[找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string?envType=problem-list-v2&envId=2cktkvj)
- 437 路径总和 III、[路径总和 III](https://leetcode.cn/problems/path-sum-iii?envType=problem-list-v2&envId=2cktkvj)
- 416 分割等和子集、[分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum?envType=problem-list-v2&envId=2cktkvj)
- 406 根据身高重建队列、[根据身高重建队列](https://leetcode.cn/problems/queue-reconstruction-by-height?envType=problem-list-v2&envId=2cktkvj)
- 399 除法求值、[除法求值](https://leetcode.cn/problems/evaluate-division?envType=problem-list-v2&envId=2cktkvj)
- 394 字符串解码、[字符串解码](https://leetcode.cn/problems/decode-string?envType=problem-list-v2&envId=2cktkvj)
- 347 前 K 个高频元素、[前 K 个高频元素](https://leetcode.cn/problems/top-k-frequent-elements?envType=problem-list-v2&envId=2cktkvj)
- 338 比特位计数、[比特位计数](https://leetcode.cn/problems/counting-bits?envType=problem-list-v2&envId=2cktkvj)
- 337 打家劫舍 III、[打家劫舍 III](https://leetcode.cn/problems/house-robber-iii?envType=problem-list-v2&envId=2cktkvj)
- 121 买卖股票的最佳时机、[买卖股票的最佳时机](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock?envType=problem-list-v2&envId=2cktkvj)
- 312 戳气球、[戳气球](https://leetcode.cn/problems/burst-balloons?envType=problem-list-v2&envId=2cktkvj)
- 309 买卖股票的最佳时机含冷冻期、[买卖股票的最佳时机含冷冻期](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown?envType=problem-list-v2&envId=2cktkvj)
- 301 删除无效的括号、[删除无效的括号](https://leetcode.cn/problems/remove-invalid-parentheses?envType=problem-list-v2&envId=2cktkvj)
- 300 最长递增子序列、[最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence?envType=problem-list-v2&envId=2cktkvj)
- 297 二叉树的序列化与反序列化、[二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree?envType=problem-list-v2&envId=2cktkvj)
- 287 寻找重复数、[寻找重复数](https://leetcode.cn/problems/find-the-duplicate-number?envType=problem-list-v2&envId=2cktkvj)
- 283 移动零、[移动零](https://leetcode.cn/problems/move-zeroes?envType=problem-list-v2&envId=2cktkvj)
- 279 完全平方数、[完全平方数](https://leetcode.cn/problems/perfect-squares?envType=problem-list-v2&envId=2cktkvj)
- 253 会议室 II、[会议室 II](https://leetcode.cn/problems/meeting-rooms-ii?envType=problem-list-v2&envId=2cktkvj)
- 240 搜索二维矩阵 II、[搜索二维矩阵 II](https://leetcode.cn/problems/search-a-2d-matrix-ii?envType=problem-list-v2&envId=2cktkvj)
- 239 滑动窗口最大值、[滑动窗口最大值](https://leetcode.cn/problems/sliding-window-maximum?envType=problem-list-v2&envId=2cktkvj)
- 22 括号生成、[括号生成](https://leetcode.cn/problems/generate-parentheses?envType=problem-list-v2&envId=2cktkvj)
- 49 字母异位词分组、[字母异位词分组](https://leetcode.cn/problems/group-anagrams?envType=problem-list-v2&envId=2cktkvj)
- 48 旋转图像、[旋转图像](https://leetcode.cn/problems/rotate-image?envType=problem-list-v2&envId=2cktkvj)
- 46 全排列、[全排列](https://leetcode.cn/problems/permutations?envType=problem-list-v2&envId=2cktkvj)
- 42 接雨水、[接雨水](https://leetcode.cn/problems/trapping-rain-water?envType=problem-list-v2&envId=2cktkvj)
- 39 组合总和、[组合总和](https://leetcode.cn/problems/combination-sum?envType=problem-list-v2&envId=2cktkvj)
- 543 二叉树的直径、[二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree?envType=problem-list-v2&envId=2cktkvj)
- 34 在排序数组中查找元素的第一个和最后一个位置、[在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array?envType=problem-list-v2&envId=2cktkvj)
- 33 搜索旋转排序数组、[搜索旋转排序数组](https://leetcode.cn/problems/search-in-rotated-sorted-array?envType=problem-list-v2&envId=2cktkvj)
- 32 最长有效括号、[最长有效括号](https://leetcode.cn/problems/longest-valid-parentheses?envType=problem-list-v2&envId=2cktkvj)
- 31 下一个排列、[下一个排列](https://leetcode.cn/problems/next-permutation?envType=problem-list-v2&envId=2cktkvj)
- 538 把二叉搜索树转换为累加树、[把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree?envType=problem-list-v2&envId=2cktkvj)
- 23 合并 K 个升序链表、[合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists?envType=problem-list-v2&envId=2cktkvj)
- 560 和为 K 的子数组、[和为 K 的子数组](https://leetcode.cn/problems/subarray-sum-equals-k?envType=problem-list-v2&envId=2cktkvj)
- 21 合并两个有序链表、[合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists?envType=problem-list-v2&envId=2cktkvj)
- 20 有效的括号、[有效的括号](https://leetcode.cn/problems/valid-parentheses?envType=problem-list-v2&envId=2cktkvj)
- 19 删除链表的倒数第 N 个结点、[删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list?envType=problem-list-v2&envId=2cktkvj)
- 17 电话号码的字母组合、[电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number?envType=problem-list-v2&envId=2cktkvj)
- 15 三数之和、[三数之和](https://leetcode.cn/problems/3sum?envType=problem-list-v2&envId=2cktkvj)
- 11 盛最多水的容器、[盛最多水的容器](https://leetcode.cn/problems/container-with-most-water?envType=problem-list-v2&envId=2cktkvj)
- 10 正则表达式匹配、[正则表达式匹配](https://leetcode.cn/problems/regular-expression-matching?envType=problem-list-v2&envId=2cktkvj)
- 5 最长回文子串、[最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring?envType=problem-list-v2&envId=2cktkvj)
- 4 寻找两个正序数组的中位数、[寻找两个正序数组的中位数](https://leetcode.cn/problems/median-of-two-sorted-arrays?envType=problem-list-v2&envId=2cktkvj)
- 3 无重复字符的最长子串、[无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters?envType=problem-list-v2&envId=2cktkvj)
- 2 两数相加、[两数相加](https://leetcode.cn/problems/add-two-numbers?envType=problem-list-v2&envId=2cktkvj)
- 79 单词搜索、[单词搜索](https://leetcode.cn/problems/word-search?envType=problem-list-v2&envId=2cktkvj)
- 114 二叉树展开为链表、[二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list?envType=problem-list-v2&envId=2cktkvj)
- 621 任务调度器、[任务调度器](https://leetcode.cn/problems/task-scheduler?envType=problem-list-v2&envId=2cktkvj)
- 617 合并二叉树、[合并二叉树](https://leetcode.cn/problems/merge-two-binary-trees?envType=problem-list-v2&envId=2cktkvj)
- 105 从前序与中序遍历序列构造二叉树、[从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal?envType=problem-list-v2&envId=2cktkvj)
- 104 二叉树的最大深度、[二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree?envType=problem-list-v2&envId=2cktkvj)
- 102 二叉树的层序遍历、[二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal?envType=problem-list-v2&envId=2cktkvj)
- 101 对称二叉树、[对称二叉树](https://leetcode.cn/problems/symmetric-tree?envType=problem-list-v2&envId=2cktkvj)
- 98 验证二叉搜索树、[验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree?envType=problem-list-v2&envId=2cktkvj)
- 96 不同的二叉搜索树、[不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees?envType=problem-list-v2&envId=2cktkvj)
- 94 二叉树的中序遍历、[二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal?envType=problem-list-v2&envId=2cktkvj)
- 85 最大矩形、[最大矩形](https://leetcode.cn/problems/maximal-rectangle?envType=problem-list-v2&envId=2cktkvj)
- 84 柱状图中最大的矩形、[柱状图中最大的矩形](https://leetcode.cn/problems/largest-rectangle-in-histogram?envType=problem-list-v2&envId=2cktkvj)
- 1 两数之和、[两数之和](https://leetcode.cn/problems/two-sum?envType=problem-list-v2&envId=2cktkvj)
- 78 子集、[子集](https://leetcode.cn/problems/subsets?envType=problem-list-v2&envId=2cktkvj)
- 76 最小覆盖子串、[最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring?envType=problem-list-v2&envId=2cktkvj)
- 75 颜色分类、[颜色分类](https://leetcode.cn/problems/sort-colors?envType=problem-list-v2&envId=2cktkvj)
- 72 编辑距离、[编辑距离](https://leetcode.cn/problems/edit-distance?envType=problem-list-v2&envId=2cktkvj)
- 70 爬楼梯、[爬楼梯](https://leetcode.cn/problems/climbing-stairs?envType=problem-list-v2&envId=2cktkvj)
- 581 最短无序连续子数组、[最短无序连续子数组](https://leetcode.cn/problems/shortest-unsorted-continuous-subarray?envType=problem-list-v2&envId=2cktkvj)
- 64 最小路径和、[最小路径和](https://leetcode.cn/problems/minimum-path-sum?envType=problem-list-v2&envId=2cktkvj)
- 62 不同路径、[不同路径](https://leetcode.cn/problems/unique-paths?envType=problem-list-v2&envId=2cktkvj)
- 56 合并区间、[合并区间](https://leetcode.cn/problems/merge-intervals?envType=problem-list-v2&envId=2cktkvj)
- 55 跳跃游戏、[跳跃游戏](https://leetcode.cn/problems/jump-game?envType=problem-list-v2&envId=2cktkvj)
- 53 最大子数组和、[最大子数组和](https://leetcode.cn/problems/maximum-subarray?envType=problem-list-v2&envId=2cktkvj)
相关推荐
WolfGang0073211 小时前
代码随想录算法训练营Day33 | 322.零钱兑换、279.完全平方数、139.单词拆分、背包总结
算法
CoderYanger1 小时前
递归、搜索与回溯-综合练习:28.不同路径Ⅲ
java·算法·leetcode·深度优先·1024程序员节
我发在否1 小时前
Rust > 牛客OJ在线编程常见输入输出练习场
算法·rust
忆湫淮1 小时前
ENVI 5.6 利用现场标准校准板计算地表反射率具体步骤
大数据·人工智能·算法
Ayanami_Reii1 小时前
基础数据结构应用-一个简单的整数问题
数据结构·算法·树状数组·fenwick tree
Ayanami_Reii1 小时前
进阶数据结构应用-一个简单的整数问题2(Fenwick-Tree 解法)
数据结构·算法·前缀和·差分·树状数组·fenwick tree
老黄编程1 小时前
点云生成深度图的原理及算法步骤和参数详细说明
数学·算法·点云·深度图
老黄编程1 小时前
点云SIFT3D特征点云原理、算法描述及参数详细说明
算法·3d·sift3d
老黄编程1 小时前
3DHarris特征提取算法描述及参数详细说明
数学·算法·几何·3dharris特征提取