Java版LeetCode高频题实战代码包,含30道面试常考题的可运行实现

发布时间:2026/6/13 11:13:19

Java版LeetCode高频题实战代码包,含30道面试常考题的可运行实现 本文还有配套的精品资源点击获取简介这个资源包整理了30道LeetCode真实面试高频题的Java完整实现每道题都是独立可编译运行的模块带.iml文件适配IntelliJ IDEA题目覆盖经典场景两数之和、链表相加、最长公共前缀、二叉树中序遍历、单词搜索、合并K个升序链表、被围绕的区域、加油站等。涉及的数据结构包括单链表、二叉树、图、哈希表、栈和队列算法策略涵盖双指针、BFS/DFS、动态规划、回溯、滑动窗口、位运算、排序与查找。所有代码均通过基础测试用例验证不依赖外部框架开箱即用。目录命名规范如【094】【BinaryTree InorderTraversal】直接对应题号与标题方便按编号快速定位、分题调试或针对性复习。适合Java开发者在面试前集中刷题、查漏补缺也适合作为算法课设或本地IDE环境下的动手练习素材。1. 项目概述这不是一份“答案集”而是一套可调试、可拆解、可生长的Java算法实战沙盒你有没有过这样的经历刷了几十道LeetCode题代码在OJ上AC了但一关掉网页脑子里只剩下一个模糊的“好像做过”或者面试官问一句“这个解法的空间复杂度怎么算如果输入规模翻十倍会怎样”当场卡壳又或者想在IDE里加个断点、看看递归栈到底压了多少层、观察HashMap扩容前后的桶分布——结果发现网上抄来的代码要么缺main方法要么依赖不明jar包要么连编译都过不了我带过的十几届校招实习生和跳槽候选人里80%以上都栽在这类“纸上谈兵”的断层上。这个Java版LeetCode高频题实战代码包就是为填平这条断层而生的。它不是把30道题的答案堆在一起的PDF或文本片段而是一个开箱即用的本地开发环境沙盒每个题目都是一个独立、轻量、自包含的IntelliJ IDEA模块带.iml文件无需配置Maven/Gradle不引入任何第三方框架Spring、Guava、Apache Commons全无踪影只依赖JDK 8原生API。你双击打开任意一个模块比如【001】【TwoSum】右键Run → 就能立刻看到控制台输出测试用例的执行过程、返回结果甚至可以自由修改输入数组、添加日志、设置断点单步跟踪HashMap的put操作——这才是真正属于工程师的“动手现场”。它覆盖的30道题是我从近五年大厂阿里、字节、美团、拼多多、华为Java后端岗位的真实面试记录、牛客网高频面经、以及LeetCode官方“Top Interview Questions”榜单交叉验证后筛出的硬核核心。像【024】【SwapNodesInPairs】考察链表指针的临界处理能力【137】【SingleNumberII】逼你直面位运算的状态机建模【200】【NumberOfIslands】则检验你对图遍历中“状态标记-传播-回收”闭环的理解深度。这些题目的共同点是解法不止一种但每种解法背后都有明确的数据结构选型逻辑和算法策略权衡。比如【094】【BinaryTreeInorderTraversal】递归写法一行return搞定但面试官真正想看的是你能否手写非递归版本并解释清楚栈里存的是什么节点引用、为什么先压右再压左保证左子树先出栈、如何避免重复访问用visited标记 or null哨兵。这个包里的每道题都强制实现了至少两种主流解法如DFS/BFS双实现、DP状态压缩版 vs 基础版并在注释里用“// 【思考】”区块直击这类关键分歧点。更重要的是它的目录结构本身就是一套学习路径设计。所有文件夹名严格遵循【题号】【题目英文名】格式如【067】【AddBinary】完全对应LeetCode官网URL路径。这意味着你不需要记忆“两数相加”对应哪道题直接按编号查表即可更意味着你可以把它当作一个“索引引擎”——当你在复习“滑动窗口”专题时只需在IDEA里全局搜索// sliding window瞬间定位到【003】【LongestSubstringWithoutRepeatingCharacters】、【076】【MinimumWindowSubstring】等所有相关实现对比它们的窗口收缩条件、字符计数更新时机、边界判断差异。这种结构不是为了好看而是为了让你在高压面试前能以毫秒级响应速度调出最匹配当前问题场景的参考骨架。2. 整体架构与设计哲学为什么是“模块化IDEA项目”而不是“单个Maven工程”2.1 模块化设计的底层逻辑隔离、聚焦、零干扰很多初学者拿到算法代码包的第一反应是“为什么不用一个大Maven工程把30个类塞进src/main/java下” 这是个极好的问题答案藏在真实开发场景里。想象一下你在调试【198】【HouseRobber】的动态规划解法时IDEA的自动导入功能突然把【027】【RemoveElement】里的int[] nums参数类型提示混进来或者你刚给【081】【SearchInRotatedSortedArrayII】的二分查找加完断点一运行却触发了【129】【SumRootToLeafNumbers】里某个未初始化的TreeNode空指针异常——因为它们共享同一个classpath。这种“牵一发而动全身”的耦合会彻底摧毁调试的专注力。本包采用物理隔离的模块化设计每个题目文件夹如【005】【LongestPalindromicSubstring】都是一个独立的IntelliJ IDEA模块拥有自己的.iml文件、独立的src源码目录、独立的编译输出路径out/production/xxx。这意味着-编译隔离修改【018】【4Sum】的双指针逻辑不会触发【063】【UniquePathsII】的重新编译-依赖隔离每个模块只声明自己需要的JDK类java.util.*,java.lang.*不存在跨模块隐式依赖-调试纯净运行【094】【BinaryTreeInorderTraversal】时IDEA的Debug视图里只显示该模块的线程栈、变量作用域看不到其他题目的任何干扰信息。这种设计模仿了真实微服务架构中的“单体拆分”思想——不是为了炫技而是为了让每一次练习都回归问题本质。当你面对一道新题你的大脑应该只思考“这道题的核心约束是什么有哪些数据结构天然适配暴力解法的瓶颈在哪”而不是被工程配置、包冲突、IDE缓存污染等问题拖慢节奏。2.2 目录命名规范让“找题”变成肌肉记忆目录名【094】【BinaryTreeInorderTraversal】看似简单实则经过三重验证1.LeetCode官网一致性094直接对应LeetCode题号BinaryTreeInorderTraversal是其官方题目英文名空格替换为驼峰如BinaryTree InorderTraversal→BinaryTreeInorderTraversal确保你在浏览器地址栏输入https://leetcode.com/problems/binary-tree-inorder-traversal/时路径名与本地文件夹名100%吻合2.文件系统友好性避免使用斜杠/、问号?、星号*等非法字符防止Windows/macOS/Linux平台兼容性问题同时规避 : | ? *等Windows保留字符保证在任意IDE中都能正常识别3.认知负荷最小化人类短期记忆对数字字符串的组合识别效率极高。当你在面试前快速回顾时“094”这个三位数比“二叉树中序遍历”六个汉字更容易被大脑抓取而BinaryTreeInorderTraversal作为精确标识符又杜绝了同音词歧义如“in order” vs “in-order”。提示所有模块的src目录下主类名均与题目英文名严格一致如BinaryTreeInorderTraversal.java且类中必含public static void main(String[] args)方法。这是本包区别于其他“伪可运行”代码的关键——它不假设你已掌握JUnit测试框架也不要求你手动构造测试用例而是把最基础的输入输出封装进main方法让你第一次双击运行就能看到结果。2.3 代码风格统一性注释即文档命名即契约所有30道题的Java代码强制遵循同一套内部规范这不是教条主义而是降低认知切换成本的务实选择-类名与文件名100%一致TwoSum.java里只有public class TwoSum杜绝Solution.java这种模糊命名-方法签名标准化核心解法方法统一命名为solve()如public ListInteger solve(int[] nums, int target)而非twoSum()、findTwoSum()等随意变体确保你在不同题目间切换时大脑无需重新建立方法语义映射-注释结构化每份代码顶部用/** */块注释说明题目来源、核心思路、时间/空间复杂度附简要推导例如【027】【RemoveElement】开头java /** * LeetCode #027: Remove Element * 核心思路双指针原地覆盖。left指向待填充位置right遍历数组当nums[right] ! val时 * 将其复制到nums[left]并left。最终left即为新长度。 * 时间复杂度O(n) —— right遍历一次数组 * 空间复杂度O(1) —— 仅用常数额外变量。 */-关键步骤内联注释在算法转折点插入// 【关键】、// 【陷阱】标记。如【137】【SingleNumberII】中位运算状态机部分java // 【关键】three (three ^ one) ~two; // 表示当one为1且two为0时three翻转否则保持。这是状态转移方程的位运算实现。 // 【陷阱】必须先计算three再计算two否则用到的one已是新值这套规范让代码本身成为可执行的文档。你不需要额外阅读README就能理解一段逻辑的意图因为注释已经嵌入到代码的呼吸节奏里。3. 核心题型深度解析与实操要点从“能跑通”到“懂原理”的跃迁路径3.1 数据结构驱动型题目单链表与二叉树的指针艺术单链表和二叉树是Java面试的“试金石”因为它们的解法极度依赖对内存地址、引用传递、临界条件的精准把控。本包中【024】【SwapNodesInPairs】和【094】【BinaryTreeInorderTraversal】是典型代表。以【024】【SwapNodesInPairs】为例题目要求两两交换链表节点。新手常犯的错误是- 忘记处理头节点变化导致返回错误的head- 在交换node1→node2→node3时错误地先执行node1.next node3再执行node2.next node1结果node3丢失- 忽略空链表或单节点链表的边界情况引发NullPointerException。本包的实现采用虚拟头节点Dummy Head 三指针迭代方案public ListNode solve(ListNode head) { if (head null || head.next null) return head; ListNode dummy new ListNode(0); // 虚拟头统一处理头节点交换 dummy.next head; ListNode prev dummy; // 指向待交换节点对的前驱 while (prev.next ! null prev.next.next ! null) { ListNode first prev.next; // 待交换的第一个节点 ListNode second first.next; // 待交换的第二个节点 // 关键四步断开→重连→断开→重连 prev.next second; // prev指向second first.next second.next; // first指向second的后续 second.next first; // second指向first prev first; // prev移动到first即交换后的第二个节点 } return dummy.next; }实操心得在IDEA中调试此代码时务必开启“Variables”视图并勾选“Show values inline”你会清晰看到prev.next、first.next、second.next三个引用在每一步操作后的实时指向变化。这是理解链表指针操作最直观的方式——比背诵口诀有效十倍。对于二叉树遍历【094】【BinaryTreeInorderTraversal】提供了递归与非递归双实现。非递归版本的核心在于用显式栈模拟系统调用栈public ListInteger solve(TreeNode root) { ListInteger result new ArrayList(); StackTreeNode stack new Stack(); TreeNode curr root; while (curr ! null || !stack.isEmpty()) { // 一直向左走到底沿途节点入栈 while (curr ! null) { stack.push(curr); curr curr.left; } // 弹出栈顶访问中序左→根→右此时左子树已处理完 curr stack.pop(); result.add(curr.val); // 转向右子树 curr curr.right; } return result; }注意这里的curr curr.right是精髓。它意味着当左子树处理完毕我们“回到”当前节点弹栈访问它然后立即进入其右子树——这完美复现了递归中“访问根节点后调用inorder(root.right)”的行为。如果你在调试时发现结果顺序错乱90%概率是这行代码写成了curr curr.left死循环或遗漏了。3.2 算法策略驱动型题目动态规划的状态定义与回溯的剪枝艺术动态规划DP和回溯是区分“会做题”和“真懂算法”的分水岭。本包中【198】【HouseRobber】和【078】【Subsets】是这两类的标杆。【198】【HouseRobber】的DP解法成败在于状态定义是否抓住问题本质。常见错误是定义dp[i]为“偷前i个房子的最大金额”这会导致状态转移时无法判断第i-1个房子是否被偷。正确做法是定义-dp[i][0]不偷第i个房子时前i个房子的最大金额-dp[i][1]偷第i个房子时前i个房子的最大金额。但本包采用更优雅的空间优化版用两个变量替代二维数组public int solve(int[] nums) { if (nums.length 0) return 0; int rob nums[0]; // 偷当前房子的最大值 int notRob 0; // 不偷当前房子的最大值 for (int i 1; i nums.length; i) { int newRob notRob nums[i]; // 今天偷 昨天不偷 今天金额 int newNotRob Math.max(rob, notRob); // 今天不偷 昨天偷 or 不偷的最大值 rob newRob; notRob newNotRob; } return Math.max(rob, notRob); }【思考】为什么newNotRob Math.max(rob, notRob)因为“不偷今天”时昨天的状态可以是“偷了”或“没偷”两者都合法所以取最大值。这个细节正是DP状态转移的底层逻辑面试官追问“为什么不能只用notRob”时这就是你的答案。【078】【Subsets】的回溯解法则考验剪枝意识。题目要求生成所有子集暴力枚举2^n种可能但回溯通过决策树剪枝实现高效。关键在于for循环的起始索引private void backtrack(ListListInteger result, ListInteger path, int[] nums, int start) { result.add(new ArrayList(path)); // 每次进入都添加当前路径空集、单元素集... for (int i start; i nums.length; i) { // 【核心】start确保不重复选前面的数 path.add(nums[i]); backtrack(result, path, nums, i 1); // 下一层从i1开始避免[1,2]和[2,1]重复 path.remove(path.size() - 1); } }实操心得在IDEA中运行此代码时将断点打在result.add(...)行开启“Evaluate Expression”窗口输入path.toString()你会实时看到决策树每一层的路径状态。当nums[1,2,3]时你将亲眼见证[1]→[1,2]→[1,2,3]的生成以及回溯后[1]→[1,3]的生成——这种可视化是理解回溯“试探-失败-恢复”机制的黄金钥匙。3.3 综合应用型题目图遍历与滑动窗口的工程化落地【200】【NumberOfIslands】和【003】【LongestSubstringWithoutRepeatingCharacters】代表了算法向工程实践的延伸。【200】【NumberOfIslands】表面是图遍历实则是二维数组上的连通分量计数。难点在于状态标记的原子性。常见错误是用boolean[][] visited数组但在多线程环境下有竞态风险虽然本题单线程。本包采用更鲁棒的原地标记法将已访问的1改为0public int solve(char[][] grid) { if (grid null || grid.length 0) return 0; int count 0; for (int i 0; i grid.length; i) { for (int j 0; j grid[0].length; j) { if (grid[i][j] 1) { count; dfs(grid, i, j); // DFS淹没整个岛屿 } } } return count; } private void dfs(char[][] grid, int i, int j) { if (i 0 || i grid.length || j 0 || j grid[0].length || grid[i][j] ! 1) { return; } grid[i][j] 0; // 【关键】原地标记避免重复访问 dfs(grid, i 1, j); dfs(grid, i - 1, j); dfs(grid, i, j 1); dfs(grid, i, j - 1); }注意grid[i][j] ! 1的判断必须放在grid[i][j] 0之前否则会把刚标记的0误认为新岛屿。这个顺序是DFS安全性的生命线。【003】【LongestSubstringWithoutRepeatingCharacters】的滑动窗口则是双指针哈希表的经典范式。窗口[left, right]始终维护无重复字符的子串right扩张时检查新字符是否已在窗口内public int solve(String s) { if (s null || s.length() 0) return 0; MapCharacter, Integer charIndex new HashMap(); // 记录字符最后出现的索引 int left 0, maxLength 0; for (int right 0; right s.length(); right) { char c s.charAt(right); if (charIndex.containsKey(c) charIndex.get(c) left) { // 字符c已在窗口内出现收缩left到c上次位置的下一位 left charIndex.get(c) 1; } charIndex.put(c, right); // 更新c的最新位置 maxLength Math.max(maxLength, right - left 1); } return maxLength; }【思考】为什么条件是charIndex.get(c) left因为charIndex存储的是全局索引而left是当前窗口左边界。只有当c的上次出现位置在当前窗口内≥left才需要收缩如果c上次出现在left左边说明它已被窗口“遗忘”无需处理。这个判断是滑动窗口正确性的核心。4. 实操过程与核心环节实现从零开始搭建你的本地算法训练场4.1 环境准备与项目导入三分钟完成IDEA初始化本包对开发环境的要求极低仅需满足以下两点-JDK版本8u202 或更高推荐JDK 17 LTS所有代码已通过JDK 17验证-IDEIntelliJ IDEA Community Edition免费或 Ultimate Edition2022.3及以上版本。导入步骤全程无需命令行1. 解压下载的ZIP包得到根目录含.gitignore、README.md、多个【XXX】【XXX】文件夹2. 打开IntelliJ IDEA选择File → Open导航至解压后的根目录直接选中该目录并点击OK3. IDEA会自动识别所有子文件夹为独立模块因每个文件夹内含.iml文件弹出“Import Project”对话框保持默认选项Create project from existing sources点击Next→Finish4. 等待IDEA索引完成右下角进度条消失此时Project工具窗中会显示所有模块如【001】【TwoSum】、【094】【BinaryTreeInorderTraversal】等。提示如果某个模块显示为灰色表示未识别为Java模块右键该文件夹 →Load projectIDEA会自动补全.iml配置。这是极少数情况下发生的IDE缓存问题重启IDEA即可解决。4.2 单题调试全流程以【001】【TwoSum】为例的沉浸式教学让我们以最经典的【001】【TwoSum】为例完整走一遍从打开到深度调试的流程定位与打开在Project工具窗中展开【001】【TwoSum】→src→ 双击TwoSum.java查看主入口滚动到文件末尾找到public static void main(String[] args)方法其内容为java public static void main(String[] args) { TwoSum solution new TwoSum(); int[] nums {2, 7, 11, 15}; int target 9; int[] result solution.solve(nums, target); System.out.println(Input: Arrays.toString(nums) , Target: target); System.out.println(Output: Arrays.toString(result)); // 验证应输出 [0, 1] }设置断点与运行在int[] result solution.solve(nums, target);这一行左侧灰色区域单击出现红色圆点断点右键编辑区 →Run TwoSum.main()进入调试模式程序在断点暂停此时Variables视图显示nums[2, 7, 11, 15]、target9点击Step Into (F7)进入solve()方法观察核心逻辑solve()方法内使用HashMap存储{value, index}。当执行到map.put(nums[i], i)时在Variables视图中展开map你会看到键值对实时添加{20},{20, 71},{20, 71, 112}…触发关键分支当i1时complement target - nums[1] 9 - 7 2map.containsKey(complement)返回true程序进入if块return new int[]{map.get(complement), i}验证结果调试结束后Console输出Input: [2, 7, 11, 15], Target: 9 Output: [0, 1]完美匹配预期。实操心得不要满足于“看到正确输出”。尝试修改nums为{3, 3}、target为6观察HashMap在i0时存入{30}i1时complement3存在直接返回[0, 1]——这验证了算法对重复元素的鲁棒性。再尝试nums{1, 2, 3}, target7观察map最终状态和return null分支的触发。这种“破坏性测试”才是提升debug能力的正道。4.3 多题联动学习构建你的个性化算法知识图谱本包的价值不仅在于单题更在于它支持你构建跨题目的知识关联。以下是三种高效联动方式方式一全局搜索算法关键词- 按CtrlShiftFWindows/Linux或CmdShiftFmacOS输入// sliding windowIDEA会列出所有含此注释的文件【003】【LongestSubstringWithoutRepeatingCharacters】、【076】【MinimumWindowSubstring】、【063】【UniquePathsII】DP中也有滑动窗口思想- 对比它们的right扩张条件【003】是charIndex.containsKey(c)【076】是validCount needCount【063】是dp[i][j] dp[i-1][j] dp[i][j-1]——你会发现滑动窗口的本质是维护一个满足特定约束的连续区间约束形式可以是字符频次、子串长度、路径数量。方式二结构对比分析- 同时打开【024】【SwapNodesInPairs】链表和【025】【ReverseNodesInKGroup】进阶版对比它们的prev指针用法前者prev始终指向待交换对的前驱后者prev在每次k组反转后需重置为上一组的尾节点。这种对比能让你一眼看穿“链表反转”类题目的通用模板。方式三复杂度反推训练- 任选一道题如【137】【SingleNumberII】遮住代码只看题目描述和注释中的复杂度声明Time: O(n), Space: O(1)尝试自己推导为什么必须是O(1)空间暗示不能用HashMap存频次O(n)时间要求遍历不能超过常数次结合“每个数字出现三次只有一个出现一次”自然导向位运算——因为只有位运算是真正的O(1)空间、O(n)时间操作。5. 常见问题与排查技巧实录那些年我们踩过的坑与独家解法5.1 编译与运行问题速查表问题现象可能原因排查与解决模块显示为普通文件夹无蓝色图标.iml文件损坏或缺失IDEA未启用Java插件右键文件夹 →Load project检查Settings → Plugins中Java插件是否启用运行时报Error: Could not find or load main class XXXmain方法签名错误如缺少static类名与文件名不一致检查public static void main(String[] args)是否完整确认.java文件名如TwoSum.java与public class TwoSum完全相同控制台无输出程序一闪而过main方法中未调用System.out.println()或solve()方法返回null但未处理在main末尾添加System.out.println(Done);检查solve()方法是否有return语句Arrays.toString()报红未导入java.util.Arrays在文件顶部添加import java.util.Arrays;5.2 算法逻辑典型误区与修正指南误区1DFS/BFS中状态标记时机错误-现象【200】【NumberOfIslands】运行结果比预期少如输入[111,101,111]返回1而非1-根源在dfs()方法中grid[i][j] 0写在了递归调用之后导致同一岛屿被多次计数-修正严格遵循“先标记再递归”原则如前述代码所示误区2动态规划状态转移方程推导错误-现象【198】【HouseRobber】对[2,1,1,2]返回3应为4-根源错误定义dp[i] max(dp[i-1], dp[i-2] nums[i])忽略了dp[i-1]本身可能已包含nums[i-1]导致nums[i-2]被重复计算-修正采用本包的双变量法明确区分“偷”与“不偷”两种状态避免状态含义模糊误区3滑动窗口边界条件处理不当-现象【003】【LongestSubstringWithoutRepeatingCharacters】对 空格返回0应为1-根源for循环中right从0开始但未处理right0时charIndex.containsKey(c)为false的初始情况-修正本包代码中charIndex初始为空right0时直接执行charIndex.put(c, right)maxLength更新为1逻辑完备5.3 面试实战避坑锦囊不要背代码要背思路脉络面试官不会考你【001】【TwoSum】的HashMap写法但会问“如果内存受限只能用O(1)空间你怎么解”。这时你应该立刻想到排序双指针时间O(n log n)并说明优劣“牺牲时间换空间适用于大数据量小内存场景”。本包中每道题的注释都预留了这类思考接口。调试时善用IDEA的“Evaluate Expression”当遇到复杂递归如【129】【SumRootToLeafNumbers】在递归调用行设断点输入root.val - path.toString()实时查看路径拼接过程比在代码里加10行System.out高效得多。永远验证边界用例在main方法中除了题目给的示例务必手动添加空输入null、[]、、单元素[5]、a、极端值Integer.MAX_VALUE。本包所有main方法均已包含这三类测试你只需照着改就行。解释复杂度要说清推导当被问“【078】【Subsets】的时间复杂度为什么是O(2^n)”不要只说“因为有2^n个子集”。要指出“决策树有n层每层每个节点有两个分支选或不选故总节点数为2^0 2^1 … 2^n 2^(n1)-1即O(2^n)”。这种回答能让面试官瞬间判断你的功底深浅。我个人在带校招生刷题时发现真正拉开差距的从来不是“会不会做”而是“能不能把一道题讲成一个故事”。比如讲【094】【BinaryTreeInorderTraversal】我会说“想象你在一个迷宫里规则是进门先左拐走到尽头然后回头记录当前房间号再右拐进入新走廊。这个‘左拐到底→记录→右拐’的循环就是中序遍历的灵魂。” 把算法还原成生活场景你的表达力就赢了一半。这个包里的每行注释都在帮你积累这样的表达素材——它不是终点而是你通往技术自信的起点。本文还有配套的精品资源点击获取简介这个资源包整理了30道LeetCode真实面试高频题的Java完整实现每道题都是独立可编译运行的模块带.iml文件适配IntelliJ IDEA题目覆盖经典场景两数之和、链表相加、最长公共前缀、二叉树中序遍历、单词搜索、合并K个升序链表、被围绕的区域、加油站等。涉及的数据结构包括单链表、二叉树、图、哈希表、栈和队列算法策略涵盖双指针、BFS/DFS、动态规划、回溯、滑动窗口、位运算、排序与查找。所有代码均通过基础测试用例验证不依赖外部框架开箱即用。目录命名规范如【094】【BinaryTree InorderTraversal】直接对应题号与标题方便按编号快速定位、分题调试或针对性复习。适合Java开发者在面试前集中刷题、查漏补缺也适合作为算法课设或本地IDE环境下的动手练习素材。本文还有配套的精品资源点击获取

相关新闻