计划对LeetCode刷题,顺便总结一下,四个阶段:

  1. 找出典型中等、困难题目,走读题目根据自己还记得的算法尝试回忆一遍
  2. 对照答案,识别自己的算法弱项,巩固算法后练习一遍典型习题
  3. 尝试找出同类型题目,巩固练习一遍
  4. 找出算法短板,重复1/2/3

算法总结

题目 我的算法 典型算法
收集树上所有苹果的最少时间 对树做剪枝,剪枝剩下的,就是要遍历的节点,剪枝的策略是DFS,复杂度On2
安排电影院座位 逐行基于阈值进行判断,计算累加结果,算法复杂度 On
通知所有员工所需时间 递归,算法复杂度 On2
爱生气的书店老板 滑动窗口,算法复杂度 On2
盛最多水的容器 暴力**,基于每个柱子进行循环遍历,算法复杂度 On2
下一个排列 暴力**,从右侧左后一个元素开始找可调整的位置,然后进行调整,On
寻找重复数 暴力**,数组先算一遍sum,然后再放入set里算一遍sum,前后两个的差就是我们要找的数字,算法复杂度 On
摆动排序 感觉是经典算法,不懂,先mark
划分字母区间 暴力**,计算每个字符的连个属性,start、end,这样就变成了基于字符的start、end计算交集、并集的问题了

收集树上所有苹果的最少时间

https://leetcode-cn.com/problems/minimum-time-to-collect-all-apples-in-a-tree/

给你一棵有 n 个节点的无向树,节点编号为 0 到 n-1 ,它们中有一些节点有苹果。通过树上的一条边,需要花费 1 秒钟。你从 节点 0 出发,请你返回最少需要多少秒,可以收集到所有苹果,并回到节点 0 。
无向树的边由 edges 给出,其中 edges[i] = [fromi, toi] ,表示有一条边连接 from 和 toi 。除此以外,还有一个布尔数组 hasApple ,其中 hasApple[i] = true 代表节点 i 有一个苹果,否则,节点 i 没有苹果。
示例 1:

【LeetCode】第一次总结。

输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,true,true,false]
输出:8
解释:上图展示了给定的树,其中红色节点表示有苹果。一个能收集到所有苹果的最优方案由绿色箭头表示。

思路:对树做剪枝,剪枝剩下的,就是要遍历的节点,剪枝的策略是DFS,复杂度On2
1、如果某个节点的子树不包含苹果,那么这个节点及其子树都不用经过
2、排除所有满足1的子树,剩下的节点都是需要遍历的
3、遍历的最小时间 = ( 节点数 - 1) * 2

安排电影院座位

链接:https://leetcode-cn.com/problems/cinema-seat-allocation

电影院的观影厅中有 n 行座位,行编号从 1 到 n ,且每一行内总共有 10 个座位,列编号从 1 到 10 。

给你数组 reservedSeats ,包含所有已经被预约了的座位。比如说,researvedSeats[i]=[3,8] ,它表示第 3 行第 8 个座位被预约了。

请你返回 最多能安排多少个 4 人家庭 。4 人家庭要占据 同一行内连续 的 4 个座位。隔着过道的座位(比方说 [3,3] 和 [3,4])不是连续的座位,但是如果你可以将 4 人家庭拆成过道两边各坐 2 人,这样子是允许的。

【LeetCode】第一次总结。

思路:逐行基于阈值进行判断,计算累加结果,算法复杂度 On
1、能够安排四人连坐,每一排最多也就能安排两个
2、对一行座位进行判断,是否满足三个场景
a. [2/3/4/5]空闲: + 1
b. [4/5/6/7]空闲: + 1
c. [6/7/8/9]空闲: + 1
经过上述三个判断,可以计算出一行能够安排的座位数
3、在2可以做一个优化,如果a为真,则直接到c的判断;如果b为真,直接返回1;如果c为真,基于a的结果进行计算

通知所有员工所需时间

链接:https://leetcode-cn.com/problems/time-needed-to-inform-all-employees/

公司里有 n 名员工,每个员工的 ID 都是独一无二的,编号从 0 到 n - 1。公司的总负责人通过 headID 进行标识。

在 manager 数组中,每个员工都有一个直属负责人,其中 manager[i] 是第 i 名员工的直属负责人。对于总负责人,manager[headID] = -1。题目保证从属关系可以用树结构显示。

公司总负责人想要向公司所有员工通告一条紧急消息。他将会首先通知他的直属下属们,然后由这些下属通知他们的下属,直到所有的员工都得知这条紧急消息。

第 i 名员工需要 informTime[i] 分钟来通知它的所有直属下属(也就是说在 informTime[i] 分钟后,他的所有直属下属都可以开始传播这一消息)。

返回通知所有员工这一紧急消息所需要的 分钟数 。

【LeetCode】第一次总结。

输入:n = 6, headID = 2, manager = [2,2,-1,2,2,2], informTime = [0,0,1,0,0,0]
输出:1
解释:id = 2 的员工是公司的总负责人,也是其他所有员工的直属负责人,他需要 1 分钟来通知所有员工。
上图显示了公司员工的树结构。

思路:递归,算法复杂度 On2
1、总耗时 = 每个员工被通知的时间之和
2、员工被通知的时间 = 上级通知他的时间 + 上级被通知的时间
3、如果上级是总负责人,则上级被通知的时间 = 0
4、基于2/3进行递归

爱生气的书店老板

链接:https://leetcode-cn.com/problems/grumpy-bookstore-owner

今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。

在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。 当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。

书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。

请你返回这一天营业下来,最多有多少客户能够感到满意的数量。

示例:

输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3
输出:16
解释:
书店老板在最后 3 分钟保持冷静。
感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.

思路:滑动窗口,算法复杂度 On2
1、基于Customers计算从0 ~ customer.length这段时间,每分钟的顾客数
2、从index = 0 开始遍历,基于每分钟的顾客数量,以及grumy值,包括但钱分钟如果使用特技的情况下带来的增益,计算出当前index+特技的顾客满意度
3、遍历到customer.length - x分钟,得出满意度最大的index

盛最多水的容器

链接:https://leetcode-cn.com/problems/container-with-most-water

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。

示例 1:
【LeetCode】第一次总结。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
思路,暴力**,基于每个柱子进行循环遍历,算法复杂度 On2
1、第一层循环,计算以每个柱子作为左边的池子容积
2、第二层循环,计算以选定左边柱子后每个柱子作为右边的池子容积
3、如果比max大,那么就更新记录容积
4、输出最大容积max

下一个排列

链接:https://leetcode-cn.com/problems/next-permutation

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须 原地 修改,只允许使用额外常数空间。

示例 1:

输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:

输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:

输入:nums = [1,1,5]
输出:[1,5,1]
示例 4:

输入:nums = [1]
输出:[1]

思路:暴力**,从右侧左后一个元素开始找可调整的位置,然后进行调整,On
1、找出下一个更大的序列,那么就要从右侧最低位优先调整
2、从右侧index位置,判断nums[index] 是否小于 nums[index - 1],如果满足,则进行调整并输出
3、如果2中index == 0,说明不存在更大序列,此时直接进行倒排输出
4、所谓的原地修改我理解就是不要拷贝复制新的数组

寻找重复数

链接:https://leetcode-cn.com/problems/find-the-duplicate-number

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

示例 1:

输入: [1,3,4,2,2]
输出: 2
示例 2:

输入: [3,1,3,4,2]
输出: 3
思路:暴力**,数组先算一遍sum,然后再放入set里算一遍sum,前后两个的差就是我们要找的数字,算法复杂度 On

摆动排序

链接:https://leetcode-cn.com/problems/wiggle-sort-ii

给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。

示例 1:

输入: nums = [1, 5, 1, 1, 6, 4]
输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6]
示例 2:

输入: nums = [1, 3, 2, 2, 3, 1]
输出: 一个可能的答案是 [2, 3, 1, 3, 1, 2]
思路:感觉是经典算法,不懂,先mark

划分字母区间

链接:https://leetcode-cn.com/problems/partition-labels

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

示例:

输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。
思路:暴力**,计算每个字符的连个属性,start、end,这样就变成了基于字符的start、end计算交集、并集的问题了
1、计算每个字符的start、end属性,得到a=[0/9],b=[2/4],c=[5/7],d=[10/16],e=[11/17],f=[12/12],j=[…]
2、这样就变成了如下图的计算问题了

【LeetCode】第一次总结。

3、遍历计算每个字符
a.如果当前字符end大于下一个字符的end,则continue
b.如果当前字符end等于下一个字符的start,则截取start到end的字符串并计算长度,同时将当前的end赋值给start,下一个字符的end赋值给当前的end
c.如果当前字符end小于下一个字符的end并且当前字符start小于下一个字符的start并且当前字符的end大于下一个字符的start,说明有交集,此时将当前字符的end赋值为下一个字符的end(字符串变大)
4、经过以上循环,得出所有字符串长度

相关文章: