leetcode 打气球
右端点排序,合并区间
美团种树
随着种树数量的增加,树总量单调递增,可以通过二分法查询种树量
美团流星
左端点和右端点分开排序,计算最大经过区间数量
右端点排序,合并区间
随着种树数量的增加,树总量单调递增,可以通过二分法查询种树量
左端点和右端点分开排序,计算最大经过区间数量
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
常规做法是通过一维数组存储当前位置作为结尾的最大子序列长度。 而根据推理可知,若在从左向右遍历时,当前元素不能与已有元素构成更长的子序列,那么替换更小的元素将有更大的可能性构成更长子序列。
1 | int lengthOfLIS(vector<int>& nums) { |
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target,返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。
1 |
|
每次迭代有 N 个选择,将 N 个选择放入堆得到排序后的值
给你一个整数 n ,请你找出并返回第 n 个 丑数 。 丑数 就是质因子只包含 2、3 和 5 的正整数。
1 | int nthUglyNumber(int n) { |
给定两个以 非递减顺序排列 的整数数组
1 | vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) { |
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
1 | int lengthOfLastWord(string s) { |
在匹配之前需要计算匹配字符串各个位置的最长重合前后缀。初始化第一个位置为 0,后缀末尾位置从 1 开始,若当前前缀的末尾与后缀末尾相同,则更新长度;否则根据当前前缀寻找新的重合前缀,这个阶段是最难理解的部分,如下图所示。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
1 | int strStr(string haystack, string needle) { |
返回 s 的任意可能的重新排列。若不可行,返回空字符串 "" 。
给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。 列表中的每个区间范围 [a,b] 应该按如下格式输出: "a->b" ,如果 a != b "a" ,如果 a == b
1 | class Solution { |
单词数组 words 的 有效编码 由任意助记字符串 s 和下标数组 indices 组成,且满足: words.length == indices.length 助记字符串 s 以 '#' 字符结尾 对于每个下标 indices[i] ,s 的一个从 indices[i] 开始、到下一个 '#' 字符结束(但不包括 '#')的 子字符串 恰好与 words[i] 相等 给你一个单词数组 words ,返回成功对 words 进行编码的最小助记字符串 s 的长度 。
若字符串s1完全与字符串s2的末尾部分或整体重合,则字符串s1可作为同一部分助记字符串 因此,可以使用Trie构建字符串树 为了正确计算包含关系,需要优先按照字符串长度倒序排序字符串
1 | class Solution { |
给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的子数组[
确定左值,向右扩展直到满足 target,记录当前窗口大小,移动左值,重复上述动作,直到右值不能再拓展
1 | class Solution { |
根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。 给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态: 1 即为 活细胞 (live),或 0 即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律: 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡; 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活; 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡; 如果死细胞周围正好有三个活细胞,则该位置死细胞复活; 下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。给你 m x n 网格面板 board 的当前状态,返回下一个状态。
使用二进制的第二位存储修改后的状态。
1 | class Solution { |
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
分别从行、列和九宫格统计数字出现次数
1 | bool isValidSudoku(vector<vector<char>>& board) { |
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。
1 | bool searchMatrix(vector<vector<int>>& matrix, int target) { |
给定一个包含若干个点的集合,求其中任意两点之间的最大/最小曼哈顿距离。
由上述式子可得:
整理合并可得:
所以,问题转换为比较点
1 | vector<int> d1; |
给定一个整数 n ,返回 n! 结果中尾随零的数量。 提示
1 | int trailingZeroes(int n) { |
给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。
相邻两个数相与,末尾的 0 将会被消除,通过移位找公共前缀得到区间相与结果
1 | int rangeBitwiseAnd(int left, int right) { |
单链表模拟
取余推测
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums 之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
正反向前缀积,使用中间变量记录累积
1 | class Solution { |
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,
将
其中,式子
1 | double myPow(double x, int n) { |
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。
统计每个二进制位 1 的出现次数,若只出现一次的数在该为为 0,那么统计次数应为 3 的倍数,否则有余数
1 | int singleNumber(vector<int>& nums) { |
另一种方法通过状态机的思想,用一个两位二进制数统计当前二进制位的状态,00 -> 01 -> 10 -> 00
1 | int singleNumber(vector<int>& nums) { |
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
1 | int majorityElement(vector<int>& nums) { |
参考题解推荐了这种方法,思考方向为若与当前假设的众数相同,则投赞成票 1,否则投否认票-1,当得票为 0 时,则继续进行假设,多数元素将获得更多投票将投票值稳定为正;另外,从代码上理解,多数元素总有更多数量的连续元素
1 | int majorityElement(vector<int>& nums) { |
有一些球形气球贴在一堵用 XY
平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中 points[i] =
[
排序,记录最小右边界(箭所能移动的最远方向),若不在射程范围内,记录新的右边界,否则更新最小右边界
给定一个二叉树的根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。
root->left->val < root->val < root->right->val
1 | int kthSmallest(TreeNode* root, int k) { |
给你链表的头结点 head ,请将其按升序排列并返回排序后的链表
归并排序链表,递归分治,子链表按序合并
各种表达式没有本质区别,他们其实是同一个语法树,只是遍历方式不同而得到的不同式子;是一个事物的一体多面,只不过是从不同角度观察罢了。
中缀表达式是其对应的语法树的中序遍历; 后缀表达式是其对应的语法树的后序遍历; 前缀表达式是其对应的语法树的前序遍历;
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
前序遍历提供根节点,中序遍历提供子树结构
1 | class Solution { |
使用栈数据结构控制遍历节点顺序,类比递归调用的栈
1 | /** |
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。 路径和 是路径中各节点值的总和。 给定一个二叉树的根节点 root ,返回其 最大路径和,即所有路径上节点值之和的最大值。
共有两种路径,一种是左右节点跨越根的环形路径,一种为父子节点的直线路径 在递归的过程中,若子树的值为负,对最大和无贡献,可置为 0,计算左右子树和根节点的和,更新当前最大值 注意递归的返回值需包含根节点,已构成完整路径
1 | class Solution { |
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
比较有趣的思路:参考
比较左右子树高度,若相等则左子树必为满树,若不相等则右子树必为满树
1 | class Solution { |