给定一个整数数组,找出所有和为 0 的三元组,结果里不能有重复的三元组(顺序无所谓)。暴力做法是三层循环加去重,时间 O(n³)。标准做法是先排序,然后固定第一个数,在它右边用双指针找另外两个数,时间降到 O(n²)。这道题真正的难点在于去重:数组里有很多重复值时,同一个三元组会
给定一个整数数组和一个目标值 target,从数组里选三个不同位置的数,使它们的和最接近 target,返回这个和。题目保证答案唯一。暴力做法是三层循环,时间 O(n³)。标准做法与三数之和一样:先排序,固定第一个数,在右侧用双指针夹逼,时间 O(n²)。这道题有两个容易写错的地
手机九宫格键盘上,数字 2 到 9 各对应几个字母(2 对应 abc,7 对应 pqrs,依此类推)。给定一个由 2 到 9 组成的数字串,返回它能表示的所有字母组合,顺序不限。这是回溯的入门题:每一位从它对应的字母里选一个,选完一位递归到下一位,走到底就收集一个结果,返回时撤销
给定一个整数数组和目标值 target,找出所有和为 target 的不重复四元组。做法是三数之和的延伸:排序后用两层循环固定前两个数,再在右侧用双指针找后两个数,时间 O(n³)。这道题相比三数之和多了一个真实的陷阱:数组元素和 target 的范围都到 10 亿,四个数相加可
给定一个链表的头结点和整数 n,删除链表的倒数第 n 个结点,返回新的头结点。倒数第 n 个不能直接定位,最直接的想法是先数出链表长度 L,再走 L - n 步找到它的前一个结点。更常见的写法是快慢指针:让 fast 先走 n 步,然后 fast 和 slow 一起走,fast
给定一个只包含 `()[]{}` 六种字符的字符串,判断括号是否有效:左括号要用同类型的右括号闭合,并且要以正确的顺序闭合。最后一条"顺序"是这道题的核心:最近打开的括号必须最先被关闭,这正是栈的后进先出。本文用真实数据展示"只数每种括号数量"这个常见的错误想法为什么不行,实测栈
把两个升序链表合并成一个升序链表,新链表由原来两个链表的结点拼接而成。做法和归并排序的合并步骤一样:两个指针各指向一条链表的当前结点,每次取较小的接到结果后面,直到一条用完,再把另一条剩下的整体接上。本文用真实数据验证一个常见的说法:递归写法更简洁,但它在 Python 里会撞上
给定 n 对括号,生成所有合法的括号组合。合法的意思是:每个右括号都能和前面某个未配对的左括号匹配。暴力做法是枚举全部 2^(2n) 个由 `(` 和 `)` 组成的串,再逐个检查;更好的做法是回溯,在生成的过程中只走合法的分支:左括号还没用满 n 个就可以放,右括号只有在"已放
给定 k 个升序链表,把它们合并成一个升序链表。最直接的想法是依次把每条链表合并到结果里,但结果越来越长,前面的结点会被反复比较。常见的更好做法有两种:用最小堆每次取出 k 个链表头里最小的;或者分治,两两合并再逐轮合并。本文选分治,因为它只需要上一题的"合并两个链表",五种语言
给定一个链表,把相邻的两个结点两两交换,返回新的头结点。要求真的交换结点,不能只交换结点里的值。链表长度是奇数时,最后一个结点保持原位。这道题没有算法上的技巧,全部难点在指针操作:每交换一对要改三个指针,顺序错了链表就断了。本文用真实的错误版本展示漏掉一步指针会得到什么,给出五种
给定一个链表,每 k 个结点一组进行翻转,返回新的头结点。如果最后剩下的结点不足 k 个,保持原样。它是反转链表的扩展:把链表切成若干段,每段单独反转再接回去。难点全在"接回去":每一组翻转之后,头变成尾、尾变成头,要正确连接前一组的尾和后一组的头。本文用真实数据展示"最后不足
给定一个升序数组,原地删除重复元素,使每个值只出现一次,返回去重之后的长度 k;数组前 k 个位置放去重后的元素,后面的内容不重要。核心是双指针:一个指针 `i` 扫描整个数组,一个指针 `k` 记录去重部分的末尾。本文实测原地写入的双指针与"遇到重复就 `del` 掉"的做法的