0%

力扣每日一题系列(2021.03.07)之分割回文串
难度:中等

0.0.1. 一、题目

给你一个字符串s,请你将s分割成一些子串,使每个子串都是回文串.返回s所有可能的分割方案.
回文串是正着读和反着读都一样的字符串.

示例1:

1
2
输入: s="aab"
输出: [["a","a","b"],["aa","b"]]

示例2:

1
2
输入: s = "a"
输出: [["a"]]

提示:

1
2
1 <= s.length <= 16
s 仅由小写英文字母组成

0.0.2. 二、题解

代码思路学习:负雪明烛

题目要求返回所有可能的结果, 那么只能暴力搜索所有可能的解,在这种情况下可以联想到使用回溯法.回溯法(算法思想)可以用递归(编程方法)来实现.

0.0.2.1. 回溯法

回溯法实际上是一个类似枚举的搜索尝试过程.
对当前搜索路径下的未探索区域进行搜索,则可能有两种情况:

  1. 当前未搜索区域满足条件,则保存当前路径并退出当前搜索
  2. 当前为搜索区域需要继续搜索,则遍历当前所有可能的选择,如果其中有选择符合要求,则把这个选择加入当前搜索路径中(递归),并继续搜索未搜索的路径

负雪明烛版本的回溯法套用模版:

1
2
3
4
5
6
7
8
9
10
11
12
res = []
path = []

def backtrack(未探索区域, res, path):
if 未探索区域满足结束条件:
res.add(path) # 深度拷贝
return
for 选择 in 未探索区域当前可能的选择:
if 当前选择符合要求:
path.add(当前选择)
backtrack(新的未探索区域, res, path)
path.pop()

其中:
backtrack表示: 未搜索区域中满足条件的所有可能路径
path表示: 一条路径
res表示: 搜索到满足的路径(将合格的path储存到res里)
path.pop()表示: 在储存一个合格路径path后,需要将其清空,以免阻碍其他搜索

本题图解

0.0.3. 三、代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution(object):
def partition(self, s):
"""
:type s: str
:rtype: List[List[str]]
"""
res = []
path = []
self.backtrack(s,res,path)
return res

def backtrack(self,s,res,path):
#指针越界,res保存这个合格的path
if not s:
res.append(path)
return
for i in range(1,len(s)+1): #i=1,2,3
#如果当下切分满足回文串的条件
if self.isSubstring(s[:i]):
#递归:考虑剩余部分的切分方法
self.backtrack(s[i:], res, path + [s[:i]])

def isSubstring(self, s):
if s == s[::-1]:
return True

0.1. Les fleurs en français

mimosa n.m 含羞草

含羞草(Mimosa pudica)是一种不寻常的植物,因为它通过折叠叶子来响应触摸。出于这个原因,它通常也被称为敏感植物。好奇的猫可能喜欢在这种植物的叶子上击球,因为它会响应他们俏皮的姿势。幸运的是,根据康涅狄格大学农业与自然资源学院的说法,如果你的猫决定蚕食一两片叶子,他就不会受到伤害:这种植物没有毒性。

Le langage des fleurs

Jaune lumière, le mimosa est riche de significations : on le compare naturellement au soleil. Il symbolise également la magnificence, l’élégance, la tendresse et délivre un message d’amitié.

含羞草淡淡的黄色,有着丰富的含义:我们它与太阳相比较。它象征着华丽,优雅,温柔并传递着友谊的信息。


tulipe n.f 郁金香

郁金香,百合科郁金香属的多年草本植物,花期是4-5月。

郁金香对猫咪有毒,临床症状为呕吐,抑郁,腹泻,过度分泌唾液。球茎中毒素浓度最高。

Le dangage des fleurs 花语

Dans le langage des fleurs, la tulipe symbolise d’une manière générale l’amour, mais avec des nuances qui varient selon sa couleur. Pourpre, elle incarne la royauté. Blanche, elle demande le pardon.
在郁金香的花语中,它一般象征着爱情,但因其颜色不同还有细微差别。比如紫色,代表着皇家气派;而纯白,则是为了表达歉意,请求原谅。

力扣每日一题系列(2021.02.27)之至少有K个重复字符的最长子串
难度:中等

0.0.1. 一、题目

给你一个字符串s和一个整数k,请你找出s中的最长子串,要求该子串中的每一字符出现次数都不少于k.返回这一子串的长度.

示例1:

1
2
3
输入:s = "aaabb", k = 3
输出:3
解释:最长子串为 "aaa" ,其中 'a' 重复了 3 次。

示例2:

1
2
3
输入:s = "ababbc", k = 2
输出:5
解释:最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。

提示:

1
2
3
1 <= s.length <= 104
s 仅由小写英文字母组成
1 <= k <= 105

0.0.2. 我的解法(30/31ac)

我的想法是先设定一个判断用的函数issubstring用于判断每一个我截取下来的子串,在这个func里,通过哈希表的方法来判断字符重复次数是否大于k,如果全部大于,返回True否则返回False.

同是判断两个边缘条件: 1)如果整个字符串为True,那就不经过下面的小循环,直接返回len(s) 2)如果k的数量大于len(s)那不可能满足,返回0.

在接下来的循环中,具体细节如下图:

但是其中continue这个想法是错误的,比如当下的substring可能不是符合条件的,但是后续补充了一些字符之后有可能这个substring是符合的,所以这种简化方法不可取,感觉这道题的用例并不是非常完全,最后这段代码只是遇到了特别长的用例时出现了时间问题,但没有遇到我提到的这个问题.

接下来是这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution(object):
def longestSubstring(self, s, k):
"""
:type s: str
:type k: int
:rtype: int
"""
def issubstring(s,k):
m = {}
for char in s:
if char in m:
m[char] += 1
else:
m[char] = 1
for char in m:
if m[char]<k:
return False
return True

if issubstring(s,k):
return len(s)
elif k > len(s):
return 0

maxlen = 0
for i in range(len(s)):
for j in range(i+k-1,len(s)):
subs = s[i:j+1]
#print(subs)
if issubstring(subs,k):
maxlen = max(maxlen,len(subs))
else:
#这个continue的想法是错误的
continue

return maxlen

0.0.3. 递归做法

依然是参考了负雪明烛的解析,这个递归我一开始有想到过,用split的方法反复切割,但是自己思路不好,就换成了上面那种做法,而且递归我一直学习的很差,得加把劲啊.

先上她的原版代码:

1
2
3
4
5
6
7
8
class Solution(object):
def longestSubstring(self, s, k):
if len(s) < k:
return 0
for c in set(s):
if s.count(c) < k:
return max(self.longestSubstring(t, k) for t in s.split(c))
return len(s)

接下来整理整理思路:

  • 递归的重点: 牢记递归函数的输入输出是什么(这里的输入是字符串,限定条件是k,输出是满足条件的最长字符子串长度)
  • 递归的终止条件: 如果字符串s的长度小于k,那么一定不存在符合条件的子串,直接返回0
  • 递归的调用法则: 如果一个字符cs中出现的次数少于k次,那么所有包含字符c的子字符串一定不符合规定.所以,应该通过某种方法将字符c排除在外,方法:把s按照字符c分割(分割后的每一个子串都不包含字符c),得到很多子串t. 而得到的t,就是未来的s'. 下一步,不含字符c的子串们t就是作为longestSubstring(s, k)的新输入,大问题分割为了小问题,形成递归.
  • 未进入递归即返回结果的情况: 如果s中的每个字符都满足大于重复次数k次的这个条件,那么直接返回len(s).

复杂度分析:

  • 时间复杂度: O(N*26*26) 因为函数最多执行26次(小写的26个英语字符),for循环遍历一遍是26个字符,循环里面对s分割时间的复杂度为O(N)
  • 空间复杂度: O(26*26), 函数执行26次,每次开辟26个字符的set空间

读聪明人的代码就是茅塞顿开的感觉,特别喜欢这个刷题姐姐的讲解

比较喜欢vim编辑器的极简化,所以慢慢整理了一些自己常用的命令

0.0.0.1. 移动光标

命令 动作
k-j-h-l 代表上-下-左-右
数字0 回到本行开头
$ 回到本行结尾
w 移到下一单词或标点的开头
W 移到下一单词的开头,忽略标点
b 移到上一单词或标点的开头
B 移到上一单词的开头,忽略标点
nG 移到第n行,注意G也是大写
:n + enter键 移到第n行
G 移到光标最后一行
H 移到当前屏幕的第一行
L 移到当前屏幕的最后一行

0.0.1. 题目描述

给你一个包含n个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a+b+c=0 ?请你找出所有和为0且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例1:

1
2
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

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

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

提示:
1
2
* 0 <= nums.length <= 3000
* -10^5 <= nums[i] <= 10^5

0.0.2. 排序➕双指针解法

三数之和这道题我一直思路不清晰,下面的代码也只是复现别人的思路,接下来总结一下:

  1. 边界条件判断,当nums不存在,或len(nums)<3的时候,返回空集合[]
  2. 对数组进行从小到大的排序
  3. 对排序后的数组开始遍历
    1. 如果nums[i]>0,由于数组已经排序过了,那么nums[i]后面的nums[L]nums[R]肯定比nums[i]更大,三个大于零的数字和不等于零。
    2. 如果nums[i]nums[i-1]是重复的,跳过
    3. 令左指针指向L = i + 1, 令右指针指向R = len(nums)-1(其实这就是最后一位)
      • 如果nums[i]+nums[L]+nums[R]=0,在答案列表里储存此组数;同时,判断nums[L+1]nums[L]是否重复,及nums[R]nums[R-1]是否重复,如果是的话,将L,R移到不再重复的位置,然后再令L=L+1,R=R-1即继续循环
      • 如果nums[i]+nums[L]+nums[R]>0, 说明右指针太大,R向左移动一位, R=R-1
      • 如果nums[i]+nums[L]+nums[R]<0,说明左指针太小,L向右移动一位,L=L+1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# 第一步:如果nums不存在或nums不到三个元素,返回空集
if not nums or len(nums) < 3:
return []

# 第二步:对nums从小到大进行排序
nums.sort()

res = []
# 第三步:对排序后的nums进行遍历
for i in range(len(nums)):
if nums[i] > 0:
return res #如果nums[i]已经大于0,因为已排序,后面不可能再有数字和nums[i]相加并等于0,返回当下答案
if i > 0 and nums[i] == nums[i-1]:
continue #如果nums[i]和nums[i-1]
L = i + 1 #当下nums[i]的右边一位
R = len(nums) - 1 #最后一位
while L < R:
if nums[i]+nums[L]+nums[R] == 0:
res.append([nums[i],nums[L],nums[R]])
while L < R and nums[L] == nums[L+1]:
#如果有重复的情况,自动移到重复最右端
L = L + 1
while L < R and nums[R] == nums[R-1]:
#如果有重复的情况,自动移到重复的最左端
R = R - 1
L = L + 1
R = R - 1
#如果和大于0,说明nums[R]太大,nums[R]向左移
elif nums[i]+nums[L]+nums[R] > 0:
R = R - 1
#如果和小于0,说明nums[L]太小,nums[L]向右移
else:
L = L + 1
return res

力扣每日一题系列(2021.02.23)之爱生气的书店老板
难度:中等

0.0.1. 一、题目

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

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

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

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

0.0.1.1. 示例

1
2
3
4
5
输入: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.

0.0.1.2. 提示

1
2
3
1 <= X <= customers.length == grumpy.length <= 20000
0 <= customers[i] <= 1000
0 <= grumpy[i] <= 1

0.0.2. 二、我的解法

我的第一个想法是利用暴力解法。(渣

通过按顺序替换grumpy里不生气的日期,再把每个新的grumpycustomers点乘求和,保存满意客户的最大数量。注意,grumpycustomers点乘前,需要注意把0(不生气)替换成1,把1(生气)替换成0,这样才能使用点乘。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution(object):
def maxSatisfied(self, customers, grumpy, X):
"""
:type customers: List[int]
:type grumpy: List[int]
:type X: int
:rtype: int
"""
#滑动窗口
res = 0
#先将grumpy里的1和0替换,方便后面点乘
#1:不生气,服务客户 0:生气,去你娘滴
grumpy = [1-i for i in grumpy]

for i in range(len(grumpy)-X+1):
grumpy_now = grumpy[:i] + [1]*X + grumpy[i+X:]
#satis:满意度列表
satis = map(lambda x,y:x*y, grumpy_now, customers)
#保留最大res
res = max(res,sum(satis))

return res

但是这个解法只ac了73/38,查看发现是那种非常长的列表无法通过。

0.0.3. 滑动窗口算法

引用思路来自: 负雪明烛

依然是滑动窗口的思路。

0.0.3.1. 1.解题思路

  • 将题目分为两部分,第一部分是不做出任何改变会留下的顾客origin,第二部分是每一个不生气窗口X的可以留下的本被赶走的客户数increse。
  • 得到的客户总数就是 origin + max(increse)

按照这个思路,我又自己写了一遍代码,ac100%了但是执行用时5.06%…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution(object):
def maxSatisfied(self, customers, grumpy, X):
"""
:type customers: List[int]
:type grumpy: List[int]
:type X: int
:rtype: int
"""
#滑动窗口
increase = 0
origin = sum(map(lambda x,y:x*y, [1-i for i in grumpy], customers))

for i in range(len(grumpy)-X+1):
grumpy_now, customers_now = grumpy[i:i+X],customers[i:i+X]
satis = 0
for j in range(len(grumpy_now)):
if grumpy_now[j] == 1:
satis += customers_now[j]
increase = max(increase,satis)
return origin + increase

所以接下来是我学习上方参考链接的做题方法写的ac100%,248ms(82.24%), 15MB(47.72%)
总体分为:

  1. 算毫无作为时满意的客户数量 origin
  2. 算滑动窗口X带来的改变 通过curValue的最大值resValue
  • 算前X个格子
  • 算第X到len(grumpy)个格子
  1. 得到结果为origin+resValue
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    class Solution(object):
    def maxSatisfied(self, customers, grumpy, X):
    """
    :type customers: List[int]
    :type grumpy: List[int]
    :type X: int
    :rtype: int
    """

    #第一步: 计算不做任何改变,满意客户的数量
    origin = sum(map(lambda x,y:x*y, [1-i for i in grumpy], customers))

    #第二步:计算滑动窗口里可以增加满意客户的数量
    # 2.1 先计算前X个格子的值
    curValue = 0
    for i in range(X):
    if grumpy[i] == 1:
    curValue += customers[i]
    resValue = curValue
    # 2.2 开始向右滑————————————
    for i in range(X,len(grumpy)):
    #先验证左边(左边滑出的那个格子)是否在生气,如果在生气,需要在curValue剪掉
    if grumpy[i-X] == 1:
    curValue -= customers[i-X]
    #再验证右边(右边新增的那个格子)是否在生气,如果在生气,需要在curValue加上
    if grumpy[i] == 1:
    curValue += customers[i]
    #判断当下curValue和史上最大curValue的关系
    resValue = max(resValue,curValue)

    return origin + resValue

0.1. 一、文章创建和发布问题

0.1.1. 常用命令

1
2
3
$ hexo g 【生成静态文件】
$ hexo d 【部署到网站或服务器,部署之前需要先生成静态文件】
$ hexo clean 【清除缓存文件(db.json)和已经生成的静态文件(public)】

0.1.2. 创建一个新的发布 Create a new Post

1
$ hexo new "My new post"

更多信息 More infowriting

0.1.3. 运行服务器 Run server

1
$ hexo server

更多信息 More info: Server

0.1.4. 生成统计文件 Generate static files

1
$ hexo generate

更多信息 More info: Generating

0.1.5. 部署到远程站点 Deploy to remote sites

1
$ hexo deploy

更多信息 More info: Deployment

0.2. 二、文章编辑问题

0.2.1. 显示不出分类、标签问题

0.2.1.1. 1.查看themes/next/_config.yml主题配置文件

打开主题配置文件_config.yml,在vim编辑器内用/搜索menu,确定categories和tags是取消注释状态的

0.2.1.2. 2.添加分类模块

在主文件夹Blog页面下

1
2
$ hexo new page categories
$ hexo new page tags

在source文件夹现在有了categories/index.mdtags/index.md两个新文件

categories/index.md为例子,应该自行添加第二行:
type: categories
注意:和categories中有一个空格

0.2.1.3. 3.文章中添加标签或分类的方法及效果

在创建新文章后的顶端添加categories或tags的名字,注意空格

最后的效果:

0.2.1.4. 4.参考

Hexo搭建博客显示不出分类、标签问题

0.2.2. Hexo博客搭建之在文章中插入图片

0.2.2.1. 1.本地引用

当中只用到少量图片时,可以将图片统一放在source/images文件夹中,通过markdown语法添加

1
$ ![](/images/image.png)

0.2.2.2. 2.相对路径

图片可以放在文章自己的目录中,需要先配置_config.yml文件,将post_asset_folder设置为true。设置完之后,在执行hexo new "post_name" 这个操作后,在source/_posts中会自动生成post_name.mdpost_name同名文件夹。这时候只需要将图片放在post_name文件夹中,文章中可以直接使用相对路径引用了。

1
$ ![](image.png)

但是!!重点来了,这个经典的markdown语句只能保证文章中可以显示出图片,但首页上不限时,很丑。可以同时显示的语句是:

1
$ {% asset_img exemple.png This is an example image %}

这时候就大功告成啦!

0.2.2.3. 3.云引用

比如一些免费的CDN服务,如Cloudinary等免费生成的url地址,直接用markdown语法引用即可。

0.2.2.4. 4.参考

Hexo博客搭建之在文章中插入图片

力扣每日一题系列(2021.02.25)之转置矩阵
难度:简单

0.1. 一、题目

给你一个二维整数数组 matrix, 返回 matrix 的 转置矩阵 。
矩阵的 转置 是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。

867.转置矩阵

0.1.1. 示例

示例1:

1
2
$ 输入: matrix=[[1,2,3],[4,5,6],[7,8,9]]
$ 输出: [[1,4,7],[2,5,8],[3,6,9]]

示例2:

1
2
输入:matrix = [[1,2,3],[4,5,6]]
输出:[[1,4],[2,5],[3,6]]

提示:
1
2
3
4
5
m == matrix.length
n == matrix[i].length
1 <= m, n <= 1000
1 <= m * n <= 105
-10^9 <= matrix[i][j] <= 10^9

0.1.2. 我的解法

转置矩阵即将M行N列的矩阵,转换成N行M列的矩阵,注意有可能N和M并不相等,所以必须要新建一个result矩阵(否则可能会出现out of range的情况)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution(object):
def transpose(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
m,n = len(matrix),len(matrix[0])
#m为行数,n为列数

#不需要numpy的矩阵建造方法
new_matrix = [[0 for i in range(m)] for i in range(n)]

for i in range(n):
for j in range(m):
new_matrix[i][j] = matrix[j][i]
return new_matrix

这道题的意思就是原来的每一行转换成了后来的每一列,为了数学关系上更清晰,下面图片为解析。可以看出,对于一个相同的元素,新地址(坐标)和旧地址(坐标)就是横纵轴交换的关系:

一个错误的思路:(这个思路就是没有考虑到新矩阵的大小关系)

1
2
3
for i in range(n):
for j in range(i,m):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]