力扣算法解题助手

209 浏览
20 试用
5 购买
Nov 5, 2025更新

本提示词专为力扣算法题目解题设计,能够系统化地分析题目需求、拆解解题步骤、提供多种解题思路并生成高效代码实现。通过结构化的问题分析方法,帮助用户深入理解算法本质,提升编程思维能力和代码实现水平。该提示词特别适合准备技术面试、学习数据结构和算法、提升编程能力的开发者使用,能够针对不同难度级别的题目提供针对性的解题指导,从问题分析到代码实现的完整解决方案。

  • 题目分析

    • 给定一个整数数组 nums 和目标值 target,要求找到两个不同的下标 i、j,使得 nums[i] + nums[j] == target,返回任意一组解的下标即可(0 基)。
    • 输入格式:
      • 第一行:整数 n(数组长度)
      • 第二行:n 个整数 nums[i]
      • 第三行:整数 target
    • 输出格式:一行输出两个整数 i j(空格分隔)
    • 约束:
      • 2 <= n <= 1e5
      • -1e9 <= nums[i], target <= 1e9
      • 保证至少存在一组解
    • 重点与边界:
      • 需要返回原始下标,不是排序后的位置
      • 可能存在重复元素
      • 可能存在负数
      • 至少一组解保证存在,算法可以在找到第一组解后立即返回
  • 解题思路

    • 思路一:暴力枚举(双层循环)
      • 对每个 i,检查所有 j > i,若 nums[i] + nums[j] == target 则返回。
      • 时间复杂度 O(n^2),空间复杂度 O(1)。
      • 在 n 可达 1e5 时不可行。
    • 思路二:哈希表一次遍历(最优推荐)
      • 使用字典记录已经遍历过的数值及其索引:map[value] = index。
      • 遍历数组当前值 x,计算补数 c = target - x。
      • 若 c 在字典中,则返回 (map[c], 当前索引);否则将 x 放入字典。
      • 保证不使用同一元素两次,因为只将“之前出现的元素”存入字典。
      • 时间复杂度 O(n),空间复杂度 O(n)。
    • 思路三:排序 + 双指针
      • 将数组元素与索引一起存储为 (value, index) 对,按 value 排序。
      • 用双指针从两端逼近求和,找到满足条件的两个索引。
      • 时间复杂度 O(n log n),空间复杂度 O(n)(存储对)。
      • 缺点:需要额外处理返回原始下标;相较哈希法更慢。
  • 算法设计(选定方案:哈希表一次遍历)

    • 初始化一个空字典 seen,用于记录已遍历过的数字及其下标。
    • 遍历 i 从 0 到 n-1:
      • 令 x = nums[i],计算补数 c = target - x。
      • 若 c 在 seen 中,返回 seen[c] 和 i。
      • 否则,将 seen[x] = i 存入字典。
    • 因为题目保证有解,遍历过程中必然能返回一组下标。
    • 边界与正确性:
      • 当 target = 2*x 且数组中有两个相等的值 x 时:第一次遇到 x 将其存入字典,第二次遇到相同 x 时其补数仍是 x,字典命中返回两个不同的索引。
      • 处理负数和大数对 Python 没有问题,整数无溢出。
  • 代码实现(Python)

import sys

def two_sum(nums, target):
    """
    返回任意一对满足 nums[i] + nums[j] == target 的不同下标 (i, j)。
    使用哈希表实现 O(n) 时间复杂度。
    """
    seen = {}  # value -> index
    for i, x in enumerate(nums):
        c = target - x
        if c in seen:
            return seen[c], i
        # 只在未命中时记录当前值及索引,确保不使用同一元素两次
        seen[x] = i
    # 按题意保证至少有解,这里理论上不会到达
    return -1, -1

def main():
    data = sys.stdin.read().strip().split()
    if not data:
        return
    # 解析输入
    it = iter(data)
    n = int(next(it))
    nums = [int(next(it)) for _ in range(n)]
    target = int(next(it))

    i, j = two_sum(nums, target)
    print(f"{i} {j}")

if __name__ == "__main__":
    main()
  • 复杂度分析

    • 时间复杂度:O(n)
      • 每个元素最多一次哈希查找与一次插入,哈希操作均摊 O(1)。
    • 空间复杂度:O(n)
      • 在最坏情况下需要存储所有已遍历元素的值与索引。
  • 测试用例

    • 基本用例(示例)
      • 输入: 4 2 7 11 15 9
      • 输出:0 1
    • 重复元素
      • 输入: 5 3 3 4 5 6 6
      • 输出:0 1(或 1 0)
    • 负数与零
      • 输入: 5 -1 0 1 2 -2 -1
      • 输出:0 1(-1 + 0 = -1)或 4 2(-2 + 1 = -1)
    • 大数与跨界组合
      • 输入: 3 1000000000 -1000000000 5 5
      • 输出:0 1(1e9 + (-1e9) = 0,不满足;正确应为 2 与某个数 -> 此例请换 target=5)
      • 更正用例: 3 1000000000 -999999995 5 5
      • 输出:0 1(1e9 + (-999999995) = 5)
    • 相同值满足 target = 2*x
      • 输入: 4 5 5 1 9 10
      • 输出:0 1(两个 5 相加等于 10)

题目分析

  • 问题本质:判断有向图是否存在环。课程之间的先修关系构成一个有向图,若图不存在有向环,则可完成所有课程;若存在环,则不可完成。
  • 输入输出:
    • 输入:
      • 第一行:numCourses(课程总数)
      • 第二行:m(先修关系条数)
      • 接下来 m 行:a b,表示课程 a 需要先修课程 b,即有边 b -> a
    • 输出:一行 "true" 或 "false"
  • 约束:
    • 1 <= numCourses <= 1e5
    • 0 <= m <= 2e5
    • 0 <= a, b < numCourses
    • 需要时间复杂度 O(numCourses + m)

解题思路

常见两种方法:

  1. 拓扑排序(Kahn 算法,BFS)

    • 思想:统计每个节点的入度,将入度为 0 的课程入队,逐步“上课”并移除其对后继课程的影响(后继入度减 1)。最终若能处理完所有课程(出队计数等于 numCourses),则无环;否则有环。
    • 优点:迭代实现,无递归栈风险;时间 O(n + m),空间 O(n + m)。
    • 适合本题大规模数据。
  2. DFS 检测环

    • 思想:对每个未访问节点进行 DFS,使用三色标记(0=未访问, 1=访问中, 2=已完成)。在访问中再次遇到访问中的节点,说明存在回边(有向环)。
    • 优点:实现简洁,直观。
    • 缺点:Java 在最坏情况下(长链)可能栈溢出;需注意递归深度限制。

对比与选择:

  • 在本题规模下(最多 1e5 节点、2e5 边),推荐使用 Kahn 拓扑排序(BFS),更稳健,不会栈溢出。DFS 方法可作为参考实现。

算法设计(选定:Kahn 拓扑排序)

  • 数据结构:
    • 邻接表 graph:ArrayList[],graph[u] 存储从 u 指向的后继 v(b -> a)
    • 入度数组 indeg:indeg[v] 表示 v 的入度
    • 队列 queue:存入所有入度为 0 的节点
  • 步骤:
    1. 初始化邻接表和入度数组。
    2. 遍历所有先修关系 (b -> a),填充 graph[b].add(a),并 indeg[a]++。
    3. 将所有入度为 0 的课程入队。
    4. 出队一个课程 u,计数 processed++;遍历 u 的后继 v,执行 indeg[v]--;若 indeg[v] == 0,则入队 v。
    5. 循环结束后,若 processed == numCourses,则返回 true;否则返回 false。
  • 边界情况处理:
    • m == 0:所有课程入度均为 0,直接返回 true。
    • 自环(a == b):会导致 indeg[a] >= 1,最终 processed < numCourses,返回 false。
    • 重边(重复的先修关系):入度会相应累加,拓扑排序正确处理。

代码实现(Java)

说明:

  • 提供两种方法:Kahn(主方法)与 DFS(参考)。
  • 包含 main 方法,按题目输入格式读取并输出结果。
  • 同时提供 LeetCode 风格的 canFinish 方法。
import java.io.*;
import java.util.*;

/**
 * 课程表(是否可修完)
 * 方法一:Kahn 拓扑排序(BFS) —— 推荐
 * 方法二:DFS 检测有向环 —— 参考(可能有递归栈风险)
 */
public class Solution {

    // LeetCode风格函数
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        return canFinishKahn(numCourses, prerequisites);
    }

    // 方法一:Kahn 拓扑排序
    public boolean canFinishKahn(int n, int[][] prerequisites) {
        // 邻接表
        List<Integer>[] graph = new ArrayList[n];
        for (int i = 0; i < n; i++) graph[i] = new ArrayList<>();
        // 入度
        int[] indeg = new int[n];

        // 构图:b -> a
        for (int[] e : prerequisites) {
            int a = e[0], b = e[1];
            graph[b].add(a);
            indeg[a]++;
        }

        // 入度为0的节点入队
        ArrayDeque<Integer> queue = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            if (indeg[i] == 0) queue.offer(i);
        }

        int processed = 0;
        while (!queue.isEmpty()) {
            int u = queue.poll();
            processed++;
            for (int v : graph[u]) {
                if (--indeg[v] == 0) {
                    queue.offer(v);
                }
            }
        }

        return processed == n;
    }

    // 方法二:DFS 检测环(参考实现)
    public boolean canFinishDFS(int n, int[][] prerequisites) {
        List<Integer>[] graph = new ArrayList[n];
        for (int i = 0; i < n; i++) graph[i] = new ArrayList<>();
        for (int[] e : prerequisites) {
            int a = e[0], b = e[1];
            graph[b].add(a);
        }
        // 0=未访问, 1=访问中, 2=已完成
        int[] state = new int[n];

        for (int i = 0; i < n; i++) {
            if (state[i] == 0) {
                if (dfsHasCycle(i, graph, state)) {
                    return false; // 有环则不可完成
                }
            }
        }
        return true;
    }

    private boolean dfsHasCycle(int u, List<Integer>[] graph, int[] state) {
        state[u] = 1; // 标记为访问中
        for (int v : graph[u]) {
            if (state[v] == 1) return true;         // 回边:有环
            if (state[v] == 0 && dfsHasCycle(v, graph, state)) return true;
        }
        state[u] = 2; // 完成
        return false;
    }

    // 主程序:按题目输入格式读取并输出
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s;

        s = br.readLine();
        if (s == null) return;
        int numCourses = Integer.parseInt(s.trim());

        s = br.readLine();
        int m = Integer.parseInt(s.trim());

        int[][] prerequisites = new int[m][2];
        for (int i = 0; i < m; i++) {
            String line = br.readLine();
            StringTokenizer st = new StringTokenizer(line);
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            prerequisites[i][0] = a;
            prerequisites[i][1] = b;
        }

        Solution sol = new Solution();
        boolean ans = sol.canFinishKahn(numCourses, prerequisites);
        System.out.println(ans ? "true" : "false");
    }
}

复杂度分析

  • 时间复杂度:
    • 构图 O(n + m)
    • Kahn 拓扑排序遍历每条边一次 O(m),每个节点入队、出队一次 O(n)
    • 总计 O(n + m)
  • 空间复杂度:
    • 邻接表存储 O(n + m)
    • 入度数组 O(n)
    • 队列最多 O(n)
    • 总计 O(n + m)

测试用例

  • 示例1:
    • 输入:
      • numCourses=2, m=1
      • 1 0
    • 输出:true
  • 示例2:
    • 输入:
      • numCourses=2, m=2
      • 1 0
      • 0 1
    • 输出:false
  • 边界用例:
    • 无先修关系:
      • 输入:numCourses=5, m=0
      • 输出:true
    • 自环:
      • 输入:numCourses=1, m=1
      • 0 0
      • 输出:false
    • 长链(压力测试,栈安全性验证对 DFS 不利):
      • 输入:numCourses=5, m=4
      • 1 0
      • 2 1
      • 3 2
      • 4 3
      • 输出:true

说明:在大规模数据下建议采用 Kahn 拓扑排序方案,避免递归带来的栈溢出风险。

题目分析

  • 目标:实现一个支持 get 和 put 操作的 LRU(最近最少使用)缓存。
  • 约束:
    • 容量 cap 与操作数 q 均可达 1e5,需要均摊 O(1) 的操作。
    • 键值可能为负数,范围 [-1e9, 1e9]。
  • 输入输出:
    • 输入 cap 与 q,然后 q 行操作:get k 或 put k v。
    • 输出所有 get 的返回值,每行一个。
  • 核心要求:使用哈希表 + 双向链表 组合,保证均摊 O(1)。

解题思路

  • 暴力(不合格):用数组或链表存键值,每次 get/put 线性查找并维护使用顺序,复杂度 O(n),在 q=1e5 时无法满足性能要求。
  • 标准解(推荐):使用
    • 哈希表(unordered_map):key -> 双向链表节点迭代器,O(1) 查找
    • 双向链表(std::list):维护使用顺序,表头为最近使用,表尾为最久未使用
  • 操作逻辑:
    • get(k):若存在,将节点移至表头并返回值;否则返回 -1
    • put(k, v):
      • 若 k 已存在:更新值并移至表头
      • 若 k 不存在:
        • 容量未满:在表头插入新节点
        • 容量已满:删除表尾节点(LRU),再在表头插入新节点
  • 数据结构选择:
    • 使用 std::list<pair<long long, long long>> 存 (key, value)
    • 使用 unordered_map<long long, list<...>::iterator> 存位置
    • 使用 list::splice 在 O(1) 时间内移动节点到表头

算法设计

  • 维护:
    • list L,头部 L.begin() 为最近使用,尾部 L.back() 为最久未使用
    • unordered_map pos:key -> L 中对应节点迭代器
  • get(key):
    1. 在 pos 中查找;不存在返回 -1
    2. 使用 splice 将该节点移到表头
    3. 返回节点的 value
  • put(key, value):
    1. cap 为 0 时直接返回(防御性处理)
    2. 在 pos 中查找:
      • 若存在:更新节点 value,splice 到表头
      • 若不存在:
        • 若 L.size() == cap:取尾节点,先在 pos 中删除其 key,再 pop_back
        • 在表头 emplace_front 新节点,并在 pos 中记录其迭代器
  • 边界与细节:
    • 负数 key/value 正常支持
    • 多次 put 同一 key,应更新并提升为最近使用
    • 仅 get 输出结果
    • 使用 fast I/O,unordered_map 预留容量以减少 rehash

代码实现(C++)

#include <bits/stdc++.h>
using namespace std;

class LRUCache {
public:
    using K = long long;
    using V = long long;
    using Node = pair<K, V>;

    LRUCache(size_t capacity) : cap(capacity) {
        // 预留哈希表空间,减少 rehash 次数
        pos.reserve(capacity ? capacity : 1);
    }

    int get(K key) {
        auto it = pos.find(key);
        if (it == pos.end()) return -1;
        // 将此节点移动到链表头部(最近使用)
        cache.splice(cache.begin(), cache, it->second);
        return static_cast<int>(it->second->second);
    }

    void put(K key, V value) {
        if (cap == 0) return; // 防御:容量为 0,则不存储任何键

        auto it = pos.find(key);
        if (it != pos.end()) {
            // 更新值并移动到头部
            it->second->second = value;
            cache.splice(cache.begin(), cache, it->second);
            return;
        }

        // 若容量已满,移除尾部(最久未使用)
        if (cache.size() == cap) {
            auto lastIt = prev(cache.end());
            K kEvict = lastIt->first;
            pos.erase(kEvict);
            cache.pop_back();
        }

        // 在头部插入新节点
        cache.emplace_front(key, value);
        pos[key] = cache.begin();
    }

private:
    size_t cap;
    list<Node> cache;                              // 双向链表:头=最近,尾=最久
    unordered_map<K, list<Node>::iterator> pos;    // 哈希:key -> 节点迭代器
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    long long cap;
    int q;
    if (!(cin >> cap)) return 0;
    cin >> q;

    LRUCache lru(static_cast<size_t>(cap));

    for (int i = 0; i < q; ++i) {
        string op;
        cin >> op;
        if (op == "get") {
            long long k;
            cin >> k;
            cout << lru.get(k) << "\n";
        } else if (op == "put") {
            long long k, v;
            cin >> k >> v;
            lru.put(k, v);
        } else {
            // 非法操作名:忽略或可选择处理,这里忽略
        }
    }
    return 0;
}

复杂度分析

  • 时间复杂度:
    • get 与 put 均为均摊 O(1)
      • 哈希查找 O(1) 平均
      • list 的 splice、插入、删除均为 O(1)
  • 空间复杂度:
    • O(cap) 存储双向链表与哈希表

测试用例

  • 示例用例:
    • 输入: 2 9 put 1 1 put 2 2 get 1 put 3 3 get 2 put 4 4 get 1 get 3 get 4
    • 输出: 1 -1 -1 3 4
  • 边界与功能覆盖:
    1. 容量为 1,频繁替换
      • 输入: 1 5 put 1 10 put 2 20 get 1 put 2 30 get 2
      • 期望输出: -1 30
    2. 重复 put 同一键提升最近性
      • 输入: 2 6 put 1 1 put 2 2 put 1 10 put 3 3 get 2 get 1
      • 期望输出: -1 10
    3. 不存在的键
      • 输入: 2 3 put 1 1 get 2 get 1
      • 期望输出: -1 1
    4. 负数键与值
      • 输入: 2 5 put -1 -100 put -2 -200 get -1 put -3 -300 get -2
      • 期望输出: -100 -1
    5. 全是 put(无输出)
      • 输入: 2 3 put 1 1 put 2 2 put 3 3
      • 期望输出:空输出(无行)
    6. 防御性测试:cap=0(若平台允许)
      • 输入: 0 4 put 1 1 get 1 put 2 2 get 2
      • 期望输出: -1 -1

该实现符合题目对 LRU 的期望:哈希表 + 双向链表,操作均摊 O(1),并覆盖常见边界情况。

示例详情

解决的问题

为正在刷力扣的学习者与面试候选人打造一套“从读题到通过”的闭环助手:快速读懂题意、拆解解题路径、对比多种方案、生成可运行的高质量代码与测试用例,并给出性能评估与优化建议。以更少时间拿到更多通过记录,形成可复用的解题套路,稳步提升面试通过率与算法思维能力。

适用用户

技术面试候选人

使用本提示词进行高频题训练,快速梳理题型与话术,生成可讲解代码与测试,用于模拟面试和查漏补缺

计算机相关专业学生

借助结构化分析完成课程作业与实验练习,理解算法原理,输出多语言题解与学习笔记,提升考试与竞赛表现

初入职开发者

用于巩固数据结构与编码规范,在空闲刷题中对照优化建议改进写法,减少线上缺陷并提高评审通过率

特征总结

针对力扣题目一键生成解题流程,从理解需求到代码实现与验证,步骤清晰全程引导
面向不同难度自动匹配解法路径,初学到进阶均可快速上手,明确该做什么与如何做
提供多角度思路对比与取舍建议,轻松看懂暴力与优化差异,迅速锁定更稳更快的方案
一键生成多语言可运行代码与注释,配套测试用例,复制即用,快速验证正确与边界
细致覆盖边界与特殊情况提醒,减少隐藏问题与面试失分,让代码更健壮更可靠
可按个人目标定制输出结构与重点,如面试速记、学习笔记、性能优化清单,满足多场景
内置常见算法模式快速联想,自动识别题型套路,帮助建立系统化刷题与拆解思维
给出效率评估与改进方向,提示可替代策略与优化点,让通过与提速兼得更有把握
支持复盘与改写指导,保留思路脉络与关键步骤,沉淀可迁移的个人题解方法库

如何使用购买的提示词模板

1. 直接在外部 Chat 应用中使用

将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。

2. 发布为 API 接口调用

把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。

3. 在 MCP Client 中配置使用

在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。

AI 提示词价格
¥30.00元
先用后买,用好了再付款,超安全!

您购买后可以获得什么

获得完整提示词模板
- 共 597 tokens
- 3 个可调节参数
{ 题目描述 } { 难度级别 } { 编程语言 }
获得社区贡献内容的使用权
- 精选社区优质案例,助您快速上手提示词
限时半价

不要错过!

免费获取高级提示词-优惠即将到期

17
:
23
小时
:
59
分钟
:
59