前言
该系列文章用于我对一周中leetcode每日一题or其他不会的题的复盘总结。
一方面用于自己加深印象,另一方面也希望能对读者的算法能力有所帮助。
该复盘对我来说比较容易的题我会复盘的比较粗糙,反之较为细致
解答语言:Golang
周一:2678. 老人的数目(easy)
题目描述:
给你一个下标从 0 开始的字符串 details
。details
中每个元素都是一位乘客的信息,信息用长度为 15
的字符串表示,表示方式如下:
- 前十个字符是乘客的手机号码。
- 接下来的一个字符是乘客的性别。
- 接下来两个字符是乘客的年龄。
- 最后两个字符是乘客的座位号。
请你返回乘客中年龄 严格大于 60 岁 的人数。
示例 1:
输入: details = ["7868190130M7522","5303914400F9211","9273338290F4010"]
输出: 2
解释: 下标为 0 ,1 和 2 的乘客年龄分别为 75 ,92 和 40 。所以有 2 人年龄大于 60 岁。
复盘:
该题就语法题了,对编程语言语法不陌生就没问题。
代码:
func countSeniors(details []string) int {
ans:=0
for _,v:=range details{
age,_:=strconv.Atoi(v[11:13])
if age>60{
ans+=1
}
}
return ans
}
周二:1155. 掷骰子等于目标和的方法数(middle)
题目描述:
这里有 n
个一样的骰子,每个骰子上都有 k
个面,分别标号为 1
到 k
。
给定三个整数 n
, k
和 target
,返回可能的方式(从总共 kn
种方式中)滚动骰子的数量,使正面朝上的数字之和等于 **target
。
答案可能很大,你需要对 109 + 7
取模 。
示例 :
输入: n = 2, k = 6, target = 7
输出: 6
解释: 你扔两个骰子,每个骰子有 6 个面。
得到 7 的和有 6 种方法:1+6 2+5 3+4 4+3 5+2 6+1。
复盘:
在做这个题的时候,其实若对完全背包比较熟悉,是比较容易能够将此题转化为完全背包的模板的。
不过能分析出如何去遍历并不是特别容易,我在做题时在这一步卡了比较久。
1.首先初始化dp函数 dp[i][j](用i个骰子掷出总数为j的组合数)
2.确定遍历步骤:由于每个骰子都有k面,所以价值j在每轮的范围应当是(0,ik)但由于价值大于target没有意义了,因此可以进行剪枝操作min(target,ik),此外还需要一层遍历去遍历当前骰子数掷出各个数字的情况进行dp状态转移
for i:=1;i<n+1;i++{
for j:=1;j<=min(target,i*k);j++{
for z:=1;z<=min(j,k);z++{
//dp
}
}
}
```
3 . 确定状态转移方程,这个是比较容易的,跟完全背包一个模板
`dp[i][j]=(dp[i][j]+dp[i-1][j-z])%(1e9+7)`
4. 根据该状态方程显然dp[0][0]-dp[0][target]是需要提前初始化的
dp[0][0]=1
## 代码:
```go
func numRollsToTarget(n int, k int, target int) int {
dp:=make([][]int,n+1)
for i:=0;i
周三:2698. 求一个整数的惩罚数(middle)
题目描述:
给你一个正整数 `n` ,请你返回 `n` 的 惩罚数 。
`n` 的 惩罚数 定义为所有满足以下条件 `i` 的数的平方和: `1 <= i <= n`
`i * i` 的十进制表示的字符串可以分割成若干连续子字符串,且这些子字符串对应的整数值之和等于 `i` 。
示例 1:
输入: n = 10
输出: 182
解释: 总共有 3 个整数 i 满足要求:
- 1 ,因为 1 * 1 = 1
- 9 ,因为 9 * 9 = 81 ,且 81 可以分割成 8 + 1 。
- 10 ,因为 10 * 10 = 100 ,且 100 可以分割成 10 + 0 。
因此,10 的惩罚数为 1 + 81 + 100 = 182
复盘:
这个题是比较容易的,直接去遍历所有数字去check是否符合惩罚数的定义再进行求和得出ans
在check的时候显然可以使用使用深搜去搜查所有的符合的情况
因为例如36*36=1296 而1296可以分为1+29+6 (符合) 12+9+6(不符合)
因此我们需要深搜得到符合的所有情况
代码:
func punishmentNumber(n int) int {
res:=0
for i:=1;i<=n;i++{
s:=strconv.Itoa(i*i)
if check(s,0,i){
res+=i*i
}
}
return res
}
//s:需要深搜的乘积 i深搜的位置 want预期结果
func check(s string,i int,want int)bool{
// 利用深搜去看每种情况是否符合
res:=0
l:=len(s)
if i>=l{
return want==0
}
for j:=i;jwant{
break
}
if check(s,j+1,want-res){
return true
}
}
return false
}
周四:2520. 统计能整除数字的位数(easy)
题目描述:
给你一个整数 `num` ,返回 `num` 中能整除 `num` 的数位的数目。
如果满足 `nums % val == 0` ,则认为整数 `val` 可以整除 `nums` 。
示例 3:
输入: num = 1248
输出: 4
解释: 1248 可以被它每一位上的数字整除,因此答案是 4 。
复盘
与周一.一致
代码:
func countDigits(num int) int {
cnt:=0
numStr:=strconv.Itoa(num)
for _,v:=range numStr{
if num%int(v-'0')==0{
cnt+=1
}
}
return cnt
}
周五:1465. 切割后面积最大的蛋糕(middle)
题目描述:
矩形蛋糕的高度为 `h` 且宽度为 `w`,给你两个整数数组 `horizontalCuts` 和 `verticalCuts`,其中:
- `horizontalCuts[i]` 是从矩形蛋糕顶部到第 `i` 个水平切口的距离
- `verticalCuts[j]` 是从矩形蛋糕的左侧到第 `j` 个竖直切口的距离
请你按数组 `horizontalCuts` 和 `verticalCuts` 中提供的水平和竖直位置切割后,请你找出 面积最大 的那份蛋糕,并返回其 面积 。由于答案可能是一个很大的数字,因此需要将结果 对 `109 + 7` 取余 后返回。
示例 1:
输入: h = 5, w = 4, horizontalCuts = [1,2,4], verticalCuts = [1,3]
输出: 4
解释: 上图所示的矩阵蛋糕中,红色线表示水平和竖直方向上的切口。切割蛋糕后,绿色的那份蛋糕面积最大。
复盘:
把长宽的切口距离最大值枚举出来相乘就是最大值,难度中等属实名不副实
代码:
func maxArea(h int, w int, horizontalCuts []int, verticalCuts []int) int {
ans:=0
maxH:=0
maxW:=0
sort.Ints(horizontalCuts)
sort.Ints(verticalCuts)
horizontalCuts=append([]int{0},append(horizontalCuts,h)...)
verticalCuts=append([]int{0},append(verticalCuts,w)...)
for i:=1;imaxW{
maxW=verticalCuts[i]-verticalCuts[i-1]
}
}
for i:=1;imaxH{
maxH=horizontalCuts[i]-horizontalCuts[i-1]
}
}
ans=maxH*maxW
return ans%1000000007
}
周六:2558. 从数量最多的堆取走礼物(easy)
题目描述:
给你一个整数数组 `gifts` ,表示各堆礼物的数量。每一秒,你需要执行以下操作:
- 选择礼物数量最多的那一堆。
- 如果不止一堆都符合礼物数量最多,从中选择任一堆即可。
- 选中的那一堆留下平方根数量的礼物(向下取整),取走其他的礼物。
返回在 `k` 秒后剩下的礼物数量 。
示例 1:
输入: gifts = [25,64,9,4,100], k = 4
输出: 29
解释:
按下述方式取走礼物:
- 在第一秒,选中最后一堆,剩下 10 个礼物。
- 接着第二秒选中第二堆礼物,剩下 8 个礼物。
- 然后选中第一堆礼物,剩下 5 个礼物。
- 最后,再次选中最后一堆礼物,剩下 3 个礼物。
最后剩下的礼物数量分别是 [5,8,9,4,3] ,所以,剩下礼物的总数量是 29 。
复盘:
每次去处最大值处理后放回,显然使用大根堆的数据结构去存储礼物每次pop出最大值即可
代码:
func pickGifts(gifts []int, k int) int64 {
hp:=&hp{}
heap.Init(hp)
for _,gift:=range gifts{
heap.Push(hp,gift)
}
for k>0{
a:=heap.Pop(hp).(int)
a=sqrt(a)
heap.Push(hp,a)
k-=1
}
ans:=0
for hp.Len()>0{
ans+=hp.Pop().(int)
}
return int64(ans)
}
type hp []int
func(h hp)Len()int{
return len(h)
}
func(h hp)Less(i,j int)bool{
return h[i]>h[j]
}
func (h *hp)Pop()interface{}{
l:=h.Len()
res:=(*h)[l-1]
*h=(*h)[:l-1]
return res
}
func (h *hp)Push(n interface{}){
*h=append(*h,n.(int))
}
func (h hp)Swap(i,j int){
h[i],h[j]=h[j],h[i]
}
func sqrt(n int)int{
ans:=0
for{
if ans*ans>n{
return ans-1
}
if ans*ans==n{
return ans
}
ans+=1
}
return ans
}
周日:274. H 指数(middle)
题目描述:
给你一个整数数组 `citations` ,其中 `citations[i]` 表示研究者的第 `i` 篇论文被引用的次数。计算并返回该研究者的 `h` 指数**。
根据维基百科上 h 指数的定义:`h` 代表“高引用次数” ,一名科研人员的 `h` 指数 是指他(她)至少发表了 `h` 篇论文,并且每篇论文 至少 被引用 `h` 次。如果 `h` 有多种可能的值,`h` 指数** 是其中最大的那个。
示例 1:
输入: citations = [3,0,6,1,5]
输出: 3
解释: 给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。
复盘:
这个题也是比较容易,当时看到题目就感觉可以直接二分法做就行,右边界为论文的最大引用数,左边界为0,去二分h指数就容易得出答案
不过当时感觉时间复杂度O(logn)可能稍微有点慢,若把每个引用数的数量都记录下来直接从大到小遍历h指数,看多少能够符合,只需要O(n)
代码:
func hIndex(citations []int) (h int) {
n := len(citations)
counter := make([]int, n+1)
for _, citation := range citations {
if citation >= n {
counter[n]++
} else {
counter[citation]++
}
}
for i, tot := n, 0; i >= 0; i-- {
tot += counter[i]
if tot >= i {
return i
}
}
return 0
}
总结
本周的题目都比较简单,easy题居多,唯一需要多花心思的是周二的骰子题目
推荐精刷(1155. 掷骰子等于目标和的方法数)