昨天忘记刷题唉😔
【算法】1013. 将数组分成和相等的三个部分
题目:
给你一个整数数组 A,只有可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false。
形式上,如果可以找出索引 i+1 < j 且满足 (A[0] + A[1] + … + A[i] == A[i+1] + A[i+2] + … + A[j-1] == A[j] + A[j-1] + … + A[A.length - 1]) 就可以将数组三等分。
示例 1:
输出:[0,2,1,-6,6,-7,9,1,2,0,1]
输出:true
解释:0 + 2 + 1 = -6 + 6 - 7 + 9 + 1 = 2 + 0 + 1
示例 2:
输入:[0,2,1,-6,6,7,9,-1,2,0,1]
输出:false
示例 3:
输入:[3,3,6,5,-2,2,5,1,-9,4]
输出:true
解释:3 + 3 = 6 = 5 - 2 + 2 + 5 + 1 - 9 + 4
解题过程
其实今天的过程还挺曲折的···主要是脑子傻傻的···啥也别说一看到,直接先上两重循环
class Solution:
def canThreePartsEqualSum(self, A: List[int]) -> bool:
# time out
for i in range(1, len(A) - 1):
for j in range(i + 1, len(A)):
part1 = sum(A[:i])
part2 = sum(A[i:j])
part3 = sum(A[j:len(A)])
if (part1 == part2) and (part2 == part3):
return True
return False
妥妥的超时了,hhh。双重循环妥妥地时间复杂度 O ( log n 2 ) O(\log n^2) O(logn2)啊。
接着想到了,每次对比part,首先得每个part都等于总和的 1 / 3 1/3 1/3,而后面两部份也要确认都等于总和的 1 / 3 1/3 1/3,那就联想到了迭代函数,于是改成以下代码:
class Solution:
# time:6956ms, beat 5.21%
# memory 18.6MB, beat 98.29%
def canTwoPartsEqualSum(self, A: List[int], possibleSum):
for i in range(1, len(A)):
part1 = sum(A[:i])
if part1 == possibleSum:
if sum(A[i:]) == possibleSum:
return True
return False
def canThreePartsEqualSum(self, A: List[int]) -> bool:
possibleSum = sum(A) / 3
for i in range(1, len(A) - 1):
if sum(A[:i]) == possibleSum:
if self.canTwoPartsEqualSum(A[i:], possibleSum):
return True
return False
成功运行,但此时还是非常耗时,为啥?看看上面的代码,时间复杂度其实还是 O log ( n 2 ) O\log(n^2) Olog(n2)啊!继续改,首先抛弃迭代函数,直接双层for循环上手,不过先对比了一下第一part的结果,依旧很耗时,因为时间复杂度仍然是 O log ( n 2 ) O\log(n^2) Olog(n2)。
首先想办法把时间复杂度降下来,怎么做呢?其实可以发现,for
循环时第二层for
循环是很没必要的,它一定会在第一part满足
1
/
3
1/3
1/3才开始,所以压根不需要这次循环,对整个列表也只需要遍历一次,我们可以用while
代替for
循环。还有一个问题,假如整个列表的和不能整除3,其实就不需要判断了,直接返回False
。于是代码改为:
class Solution:
def canThreePartsEqualSum(self, A: List[int]) -> bool:
# time:7284ms, beat 5.21%
# memory: 18.4MB, beat 98.29%
if sum(A) % 3:
return False
possibleSum = sum(A) // 3
i = 1
while i < len(A) - 1:
if sum(A[:i]) == possibleSum:
break
i += 1
if i == len(A) - 1:
return False
j = i + 1
while j < len(A):
if sum(A[i:j]) == possibleSum:
return True
j += 1
return False
运行成功了,但时间还是很长很长。仔细品品,为啥都while
遍历列表了,还蠢蠢地用sum()
···
最终改为:
class Solution:
def canThreePartsEqualSum(self, A: List[int]) -> bool:
# time:72ms, beat 96.60%
# memory: 18.8MB, beat 98.29%
if sum(A) % 3:
return False
possibleSum = sum(A) // 3
i = 0
part1 = 0
while i < len(A) - 2:
part1 += A[i]
i += 1
if part1 == possibleSum:
break
if i == len(A) - 2:
return False
part2 = 0
while i < len(A) - 1:
part2 += A[i]
if part2 == possibleSum:
return True
i += 1
return False
运行结果:
执行用时 :72 ms, 在所有 Python3 提交中击败了96.60%的用户
内存消耗 :18.8 MB, 在所有 Python3 提交中击败了98.29%的用户
【数据库】176. 第二高的薪水
题目
编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。
±—±-------+
| Id | Salary |
±—±-------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
±—±-------+
例如上述 Employee 表,SQL查询应该返回 200 作为第二高的薪水。如果不存在第二高的薪水,那么查询应返回 null。
±--------------------+
| SecondHighestSalary |
±--------------------+
| 200 |
±--------------------+
解决办法
# Write your MySQL query statement below
SELECT
IFNULL((SELECT DISTINCT Salary FROM Employee
ORDER by Salary DESC
LIMIT 1 OFFSET 1),
null
) AS SecondHighestSalary;
以上LIMIT n
代表查询结果返回前n条数据,OFFSET n
表示跳过n条数据。所以LIMIT x OFFSET y
就是跳过y条数据,然后再返回前x条数据。以上也可以用LIMIT y, x
来替换LIMIT x OFFSET y
。IFNULL( , )
根据字面意思,其实就是如果查询不到,就返回null
。
撒花~