LEETCODE刷题记录(JAVA/SQL/C)

说明

本文题目涉及代码均在我的Github,文件名为leetcode\题目编号

算法

简单

1 两数之和

【难度】★☆☆☆☆
【代码】1\Solution.c

121 买卖股票的最佳时机

【难度】★☆☆☆☆
【题目分析】给定数组求求最大单向数组元素差
【题解】直接暴力
【时间复杂度】O(n2)
【代码】121\Solution.java
【优化】时间复杂度降到O(nlog2n)

169 多数元素

【难度】★☆☆☆☆
【题目分析】求众数
【题解】用HashMap记录映射关系即可【4】
【时间复杂度】
【代码】169\Solution.java

409 最长回文串

【难度】★☆☆☆☆
【题目分析】统计给定字符集可以构造出的最长回文串长度
【题解】简单的统计计数
【代码】409\Solution.java

543 二叉树的直径

【难度】★★☆☆☆
【题目分析】求二叉树最长子路径
【题解】
ans=max{左子树ans,右子树ans,经过root最长路径}
经过root最长路径=左子树depth+右子树depth+分叉数
【时间复杂度】O(nlog2n)
n个节点,高度log2n
求depth时会遍历所有节点,所以求depth的复杂度O(n)
求解过程如下
f ( n ) = 2 f ( n 2 ) + O ( n ) = 2 [ 2 f ( n 4 ) + O ( n 2 ) ] + O ( n ) = 4 f ( n 4 ) + 2 O ( n ) = 8 f ( n 8 ) + 3 O ( n ) . . . = n f ( 1 ) + l o g   2   n O ( n ) = n O ( 1 ) + l o g   2   n O ( n ) = O ( n ) + l o g   2   n O ( n ) = O ( n l o g   2   n ) f(n)=2f(\frac n 2)+O(n)\\ =2[2f(\frac n 4)+O(\frac n 2)]+O(n)\\ =4f(\frac n 4)+2O(n)\\ =8f(\frac n 8)+3O(n)\\ ...\\ =nf(1)+log~2~nO(n)\\ =nO(1)+log~2~nO(n)\\ =O(n)+log~2~nO(n)\\ =O(nlog~2~n)\\ f(n)=2f(2n)+O(n)=2[2f(4n)+O(2n)]+O(n)=4f(4n)+2O(n)=8f(8n)+3O(n)...=nf(1)+log 2 nO(n)=nO(1)+log 2 nO(n)=O(n)+log 2 nO(n)=O(nlog 2 n)
【代码】543\Solution.java

892 三维形体的表面积

【难度】★★☆☆☆
【题目分析】在一个平面上堆长宽高都为1的立方体,问最后堆成的三维体表面积,给定 g r i d grid grid数组,表示在每个格子堆积的立方体数量
【题解】在垂直方向投影很好理解,只要那个格子有堆立方体,不管堆了几个,都是上下各算一次表面积;在两个水平方向上是对称的,只用考虑一个方向上的思路,另一个同理,在某一个水平方向上的投影,每一行(列)都是独立的,所以也只要考虑单独某一行在水平方向上的表面积,一开始我没有考虑凹的情况,单纯的只考虑了最高点,实际是要考虑到每一个局部极值点,见下图:
LEETCODE刷题记录(JAVA/SQL/C)_第1张图片
把h1,h2…这些高度差加起来就是水平方向上的表面积
时间复杂度是 O ( n 2 ) O(n^2) O(n2)
【代码】892\Solution.java

836 矩形重叠

【难度】★☆☆☆☆
【题目分析】给定2个矩形坐标,判断是否重叠
【题解】简单的计算几何,时间复杂度 O ( 1 ) O(1) O(1)
【代码】836\Solution.java

914 卡牌分组

【难度】★☆☆☆☆
【题目分析】给定数组,判断能否将数组分为若干个子数组,使得每个子数组元素个数相同且元素值也相同,要求每个子数组至少有2个元素,可以只有一个子数组(即不划分)
【题解】设数组中有 k k k种不同的数字,每种数字分别有 c n t i ( i = 1 , . . . , k ) cnt_i(i=1,...,k) cnti(i=1,...,k)个,则需满足:
g c d ( c n t 1 , . . . , c n t k ) > 1 gcd(cnt_1,...,cnt_k)>1 gcd(cnt1,...,cntk)>1
n = 1 n=1 n=1时也就是 g c d ( c n t 1 ) = c n t 1 > 1 gcd(cnt_1)=cnt_1>1 gcd(cnt1)=cnt1>1
【时间复杂度】设有 n n n个元素,总共有 k k k种数,每种数字分别有 c n t i ( i = 1 , . . . , k ) cnt_i(i=1,...,k) cnti(i=1,...,k)个,那么就要求 k − 1 k-1 k1 g c d gcd gcd
首先讨论一下 g c d gcd gcd的时间复杂度,考虑到 g c d ( x , y ) gcd(x,y) gcd(x,y)会生成的序列是
x , y , x % y , y % ( x % y ) , . . . x,y,x\%y,y\%(x\%y),... x,y,x%y,y%(x%y),...
设生成的序列为 { a n } \{a_n\} {an},则 a 0 = x , a 1 = y , a i = a i − 2 % a i − 1 a_0=x,a_1=y,a_i=a_{i-2}\%a_{i-1} a0=x,a1=y,ai=ai2%ai1
于是可以得到:
a i < a i − 1 a_iai<ai1

a 2 ≤ y − 1 , a 3 ≤ y − 2 , . . . , a y ≤ 1 , a y + 1 ≤ 0 a_2\leq y-1,a_3\leq y-2,...,a_y\leq 1,a_{y+1}\leq 0 a2y1,a3y2,...,ay1,ay+10
因此数列 { a n } \{a_n\} {an}一定是有限数列,且元素个数 n ≤ y + 2 n\leq y+2 ny+2,通俗的说来就是通过取模运算得到的数一定比之前的数至少要小1,所以最多经过 y y y次取模,就一定能得到最大公约数,所以 g c d gcd gcd的时间复杂度就是 O ( m a x ( x , y ) ) = O ( x + y ) O(max(x,y))=O(x+y) O(max(x,y))=O(x+y)
那么回到本题求 k k k g c d gcd gcd的时间复杂度就是
O ( ∑ i = 1 k c n t i ) = O ( n ) O(\sum_{i=1}^k cnt_i)=O(n) O(i=1kcnti)=O(n)
【代码】914\Solution.java

999 车的可用捕获量

【难度】★☆☆☆☆
【题目分析】给定棋盘,只有白方小兵,黑方小兵,白方车(上下左右无限距离),问有几个黑方小兵在白方一步到胃的位置
【题解】模拟即可,时间复杂度 O ( n 2 ) O(n^2) O(n2)
【代码】999\Solution.java

1013 将数组分成和相等的三个部分

【难度】★★☆☆☆
【题目分析】判断数组是否可划分为和相等的三部分
【题解】
首先计算一个累加和数组;
如果总和不为3的倍数直接false
将总和除3得到每部分的目标值
枚举第1部分的值,只有当它的值符合目标值时才枚举第2部分的值,如果第2部分的值也为目标值则直接true
枚举结束还没有则false
【时间复杂度】 O ( n 2 ) O(n^2) O(n2)
计算累加和复杂度 O ( n ) O(n) O(n)
枚举部分复杂度 O ( n 2 ) O(n^2) O(n2)
【代码】1013\Solution.java
【优化】最坏情况的 O ( n 2 ) O(n^2) O(n2)是当每次枚举第1部分的值都符合目标值,但是枚举第2部分的目标值都不符合,这种情况的数据就是 [ x , 0 , 0 , . . . , 0 , x , x ] [x,0,0,...,0,x,x] [x,0,0,...,0,x,x],因此如果想要继续优化,则要对连续的0作记录,比如说跳过连续的0,因为这些0并不会影响局部和;另一个思路是在枚举和时二分位置这样有望将时间复杂度降到 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

1071 字符串的最大公因子

【难度】★☆☆☆☆
【题目分析】求2个字符串最长公因子串
【题解】暴力枚举这个公因子串即可,排除掉长度不能整除的
【代码】1071\Solution.java
【时间复杂度】 O ( n 2 ) O(n^2) O(n2)其中 n n n为较短字符串的长度
【优化】公因子串长度只可能是2个字符串长度的公约数,所以先计算出最小公约数,再倍增枚举会更快,另外从长往短会更快,因为短的即使匹配成功了还要试长的,但是长的如果匹配成功了就直接结束了

1160 拼写单词

【难度】★☆☆☆☆
【题目分析】判断给定单词是否能被给定符号表示(每个符号只能用1次)
【题解】暴力模拟即可
【时间复杂度】单词数 n n n,单词最大长度 m m m,符号表长度 k k k O ( n m k ) O(nmk) O(nmk)
【代码】1160\Solution.java
【优化】将符号表排序,每次匹配降到对数级别,时间复杂度可以降到 O ( n m l o g 2 k ) O(nmlog_2k) O(nmlog2k)

1480 一维数组的动态和

【难度】★☆☆☆☆
【代码】1480\Solution.c
【注C】returnSize变量无须分配内存

中等

200 岛屿数量

【难度】★★☆☆☆
【标签】搜索
【题目分析】给定01矩阵,求连通块数量
【题解】广度优先搜索或深度优先搜索均可,时间复杂度 O ( n m ) O(nm) O(nm)
【代码】200\Solution.java

300 最长上升子序列

【难度】★★☆☆☆
【标签】动态规划
【题目分析】求最长上升子序列长度
【题解】数组 { a n } \{a_n\} {an} f ( i ) f(i) f(i)表示以 a i a_i ai结尾的最长上升子序列长度,状态转移方程为:
f ( i ) = max ⁡ 0 ≤ j < n , a j < a i f ( j ) f(i)=\max_{0\leq jf(i)=0j<n,aj<aimaxf(j)
【时间复杂度】 O ( n 2 ) O(n^2) O(n2)
【代码】300\Solution.java
【进阶】 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)算法【5】【6】

355 设计推特

【难度】★☆☆☆☆
【标签】应用题、模拟
【题目分析】给定推特的几个基本功能模块需求,实现这些需求(发推、关注、取关、获取最近的推特)
【题解】维护一个follow关系的集合,再维护一个发推的List,各种操作都围绕这两个数据结构进行增删改查
【代码】355\Twitter.java

365 水壶问题

【难度】★★★☆☆
【标签】搜索、数论
【题目分析】给定2个容量分别为 x x x y y y的水壶问能否经过若干次操作后得到体积为 z z z的水
【题解】一开始想着用深搜,用布尔数组去重的话内存为炸,所以考虑用集合来进行去重;结果用了集合还是炸内存,所以考虑有更优解法,考虑这四种操作都是 x x x y y y的线性组合看,所以联想到裴蜀定理,即判断 z z z是否能被 g c d ( x , y ) gcd(x,y) gcd(x,y)整除,然后另外考虑一些特殊情况:
(1) x + y < z x+yx+y<z
(2) x x x y y y中有 0 0 0
(3) z z z为0
【代码】365\Solution.java;365\Solution_Brutal.java
【优化】不过现在想来用深搜也不是不可以,可能注意剪枝之后也可以

695 岛屿的最大面积

【难度】★★☆☆☆
【标签】搜索
【题目分析】求01矩阵中在水平或垂直方向连通的最多的1的数量
【题解】深度优先搜索,原始矩阵外围添加一层0更加便利
【时间复杂度】由于每个格子最多访问1次所以就是 O ( m n ) O(mn) O(mn) m , n m,n m,n分别为矩阵长宽
【代码】695\Solution.java

820 单词的压缩编码

【难度】★★☆☆☆
【题目分析】给定若干单词,要求按照如下方式进行压缩编码:如果一个单词是另一个单词的后缀,那么只保留那个较长的单词,单词之间用“#”连接,另外用一个数组记录每个单词在压缩后字符串中的起始位置,还原的时候就从起始位置开始一直到“#”结束,要求输出最短的压缩后字符串长度
【题解】用一个数组 q q q记录压缩后保留的单词,依次枚举每一个原始单词,如果这个单词是 q q q中某一个单词的后缀,那么就无需保留这个原始单词,如果这个单词的后缀是 q q q种某一个单词,那么就用这个单词替换 q q q中的那个单词,否则就将这个单词加入 q q q,最后统计 q q q中单词总长度,并且加上“#”的数量(也就是 q q q中的单词数量),如果有 n n n个单词,单词长度最长为 l l l,那么时间复杂度就是 O ( n 2 l ) O(n^2l) O(n2l)
【代码】820\Solution.java
【优化】如果把 q q q中弄成有序结构,是否有可能把复杂度降到 O ( n l l o g 2 n ) O(nllog_2n) O(nllog2n)呢?

912 排序数组

【难度】★☆☆☆☆
【标签】排序
【题目分析】给定数组按升序排序
【题解】直接用sort函数即可,不过这题的本意应该是自己手写排序函数,不然也不会放在中等里了,有机会再补一下各种版本的手写排序版本吧
【代码】912\Solution.java

945 使数组唯一的最小增量

【难度】★★☆☆☆
【标签】模拟
【题目分析】给定一个向量 a a a,求一个向量 b b b使得这两个向量之和的各分量均不相同,即 c = a + b , c i c=a+b,c_i c=a+b,ci互不相同,要求输出 ∑ b i \sum b_i bi
【题解】时间复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
首先排序,时间复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
接着从最小的开始遍历,设 p r e n u m prenum prenum=为上一个值, n o w n u m nownum nownum表示当前值, p l a t n u m platnum platnum表示目前还不能保证唯一的数的个数, h e i g h t height height表示当前值和前一个值之间的差, a n s ans ans记录累加的和,则按照如下公式更新:
p l a t n u m = { p l a t n u m + 1 , h e i g h t = 0 p l a t n u m − h e i g h t − 1 , 0 < h e i g h t < p l a t n u m 0 , h e i g h t ≥ p l a t n u m platnum= \left\{ \begin{aligned} &platnum+1&,height=0\\ &platnum-height-1&,0platnum=platnum+1platnumheight10,height=0,0<height<platnum,heightplatnum
a n s = { a n s , h e i g h t = 0 a n s + ( h e i g h t − 1 ) ⋅ h e i g h t 2 + ( p l a t n u m − h e i g h t − 1 ) ⋅ h e i g h t , 0 < h e i g h t < p l a t n u m a n s + ( 1 + p l a t n u m ) ⋅ p l a t n u m 2 , h e i g h t ≥ p l a t n u m ans= \left\{ \begin{aligned} &ans&,height=0\\ &ans+\frac {(height-1)\cdot height} 2+(platnum-height-1)\cdot height&,0ans=ansans+2(height1)height+(platnumheight1)heightans+2(1+platnum)platnum,height=0,0<height<platnum,heightplatnum
上述公式的解释是这样的,当前后值没有落差时,则继续积累“无家可归者”;当前后落差非常大时(超过“无家可归者”数量),则所有当前“无家可归者”都有地方住了,更新一下计数;当前后有落差但是不够大时(不够所有“无家可归者”数量),那么先安置能够安置的,然后剩下的要把数字提升到当前的 n o w n u m nownum nownum,也就是统一升高 h e i g h t height height,等待下一次产生落差时再一起分配,如果已经是最后一个数字了,那么就一次性把所有待分配位置的“无家可归者”给安排了。
【代码】945\Solution.java

1162 地图分析

【难度】★★★☆☆
【标签】搜索
【题目分析】给定一张包含0和1的二维地图,其中0和1分别代表海洋和陆地,要求输出最远的海陆距离,这里的距离是曼哈顿距离,即求:
max ⁡ ( i 1 , j 1 ) = 0 { min ⁡ ( i 2 , j 2 ) = 1 ∣ i 1 − i 2 ∣ + ∣ j 1 − j 2 ∣ } \max_{(i_1,j_1)=0}\{\min_{(i_2,j_2)=1}|i_1-i_2|+|j_1-j_2|\} (i1,j1)=0max{(i2,j2)=1mini1i2+j1j2}
【题解】地图规模是 100 × 100 100\times100 100×100,也就是有 1 0 4 10^4 104个点,最容易想到的思路就是暴力,每两个点计算一下距离,这样的复杂度就是 O ( 1 0 8 ) O(10^8) O(108),设地图的边长为 n n n,即时间复杂度为 O ( n 4 ) O(n^4) O(n4),写了一下超时了;实际上还有一个广搜的思路,可以把时间复杂度降到 O ( n 2 ) O(n^2) O(n2),也就是从陆地出发(海陆距离为0),将所有陆地放到队列里,然后再一个个出队,每个点出队就把它周围的4个点入队(海陆距离+1),当然如果有的点之前已经入队过了就不用再入队了,每个点都只会入队一次并出队一次,最后那个入队的点的海路距离就是题目所求的海陆距离,总共有 n 2 n^2 n2个点,所以时间复杂度就是 O ( n 2 ) O(n^2) O(n2)
【代码】
1162\Solution_brutal.java
1162\Solution.java

困难

数据库

简单

175 组合两个表

【题目分析】一张人名信息表,一张住址表,要输出人名及其对应的住址,即使没有住址也要输出人名
【题解】left join【7】
【代码】175\Solution.sql

181 超过经理收入的员工

【题目分析】给定员工信息表,包含员工ID,姓名,工资,和上级ID,如果这个员工本身就是上级,那么上级ID就是null,要求出工资比上级大的员工姓名,最后输出的属性名要设置为Employee
【题解】将表与自身进行join连接
【代码】181\Solution.sql

182 查找重复的电子邮箱

【题目分析】一张表只有2个属性(其中1个是id),要求输出其中重复的条目
【题解】使用group by having 和count()聚合函数
【代码】182\Solution.sql
【思考】1.where为什么不能用聚合函数2.where group by having的顺序为什么是这样的3.执行group by然后having的内部细节是怎样的

183. 从不订购的客户

【题目分析】给定2张表,1张是客户名单,另一张是订单记录,要求输出所有没有下过订单的客户名字
【题解】提供3种解法,Solution1是在where子句中用not in判断客户id有没有在订单记录中,Solution2是将客户名单left join订单记录,然后输出这样操作后右边is null的客户,虽然Solution2通过了leetcode的测试,但是我觉得其实还是有问题的,因为这样输出可能会有重复的客户,所以Solution3就是在Solution2的基础上加了一个去重distinct,不过需要注意的是,这里distinct的不是Name,而是(Name,Id)元组,因为有可能存在重名的人,有趣的是,Solution3的执行时间是最快的,这其中的原理还没有深究
【代码】183\Solution1.java;183\Solution2.java;183\Solution3.java
【思考】为什么Solution3在Solution2的基础上加上distinct的去重操作之后反而更快了?

196 删除重复的电子邮箱

【题目分析】给定一张表,表中有id和对应的邮箱,要求删除重复的邮箱,对于重复的邮箱只保留id最小的那行记录,要求必须使用delete语句
【题解】按照每个邮箱分组,得到min(id)子表,然后将原表中id不在这个min(id)子表中的记录都delete掉,需要注意的是如果直接写delete from 表A where 属性名 not in(select 属性名 from 表A…)这样会报错,必须要将子表的结果再select一遍才行,这是mysql特有的问题,像oracle就不用再select一遍【9】
【代码】196\Solution.sql

197 上升的温度

【题目分析】给定天气表,包含id,日期,温度,要求输出所有升温日期(比前一天温度要高)对应的id
【题解】自己join自己;DATE_ADD函数
【代码】197\Solution.sql

595 大的国家

【题目分析】一张表包含国名、人口、面积,要求找到其中人口超过一定规模或面积达到一定规模的国家
【题解】where子句
【代码】595\Solution.sql

620 有趣的电影

【题目分析】给定包含电影编号、名字、描述、得分的表,要求输出奇数编号,描述不无聊的电影,按照得分从高到低排序
【题解】字符串要加引号;order by desc
【代码】620\Solution.sql

627 交换工资

【题目分析】要求把表格中的性别男女互换,要求只能用一个update,不能用select
【题解】使用if或者case when
【代码】
627\Solution_case.sql
627\Solution_if.sql

中等

困难

Shell

多线程

简单

1114 按序打印

【题目】A,B,C三个线程先后启动调用打印语句,要求最终的打印序列一定是"firstsecondthird"
【题解】想到设一个变量初始为0,然后只有打印完"first"后才加1,然后打印"second"的语句一定要等到它为1时才执行,"third"同理,不过只用普通的int是不行的,甚至volatile也不行,必须要用AtomicInteger才行【10】
【代码】leetcode\1114

中等

困难

程序员面试金典

简单

面试题01.06. 字符串压缩

【难度】★☆☆☆☆
【题目分析】对给定字符串进行压缩,压缩方法为将重复的字符用数字表示
【题解】模拟即可
【时间复杂度】 O ( l e n ) O(len) O(len)
【代码】01.06\Solution.java

面试题17.16. 按摩师

【难度】★★☆☆☆
【题目分析】给定 n u m s nums nums数组,求最大的不连续子数组和
【题解】动态规划,时间复杂度 O ( n ) O(n) O(n)
状态转移方程, f ( i ) f(i) f(i)表示以 n u m s [ i ] nums[i] nums[i]结尾的最大不连续子数组和:
f ( i ) = { n u m s [ 0 ] , i = 0 n u m s [ 1 ] , i = 1 n u m s [ 0 ] + n u m s [ 1 ] , i = 2 m a x ( f ( i − 2 ) , f ( i − 3 ) ) + n u m s [ i ] , i ≥ 3 f(i)= \left\{ \begin{aligned} nums[0],i=0\\ nums[1],i=1\\ nums[0]+nums[1],i=2\\ max(f(i-2),f(i-3))+nums[i],i\geq 3\\ \end{aligned} \right. f(i)=nums[0],i=0nums[1],i=1nums[0]+nums[1],i=2max(f(i2),f(i3))+nums[i],i3
【代码】17.16\Solution.java

中等

困难

剑指OFFER

简单

面试题40. 最小的k个数

【难度】★☆☆☆☆
【题目分析】找出给定数组中最小的k个数
【题解】排序后输出即可
【代码】OFFER.40\Solution.java

面试题62. 圆圈中最后剩下的数字

【难度】★☆☆☆☆
【题目分析】约瑟夫问题,输出最后的剩的数字
【题解】暴力模拟即可
【代码】OFFER.62\Solution.java
【优化】约瑟夫问题数学解【8】

中等

困难

参考文献

【1】Latex参考文档
【2】在线latex工具
【3】Cmd Markdown 公式指导手册
【4】【简易版】HashMap(增删改查)
【5】最长上升子序列o(nlogn)复杂度一种简单易懂的理解
【6】最长递增子序列
【7】SQL的各种连接Join详解
【8】约瑟夫问题的三种解法
【9】You can’t specify target table ‘表名’ for update in FROM clause错误
【10】按序打印

END

你可能感兴趣的:(LEETCODE刷题记录(JAVA/SQL/C))