6136. 算术三元组的数目
给你一个下标从 0 开始、严格递增 的整数数组 nums 和一个正整数 diff 。如果满足下述全部条件,则三元组 (i, j, k) 就是一个 算术三元组 :
- i < j < k ,
- nums[j] - nums[i] == diff 且
- nums[k] - nums[j] == diff 返回不同 算术三元组 的数目。
示例1
输入:nums = [0,1,4,6,7,10], diff = 3
输出:2
解释:
(1, 2, 4) 是算术三元组:7 - 4 == 3 且 4 - 1 == 3 。
(2, 4, 5) 是算术三元组:10 - 7 == 3 且 7 - 4 == 3 。
示例2
输入:nums = [4,5,6,7,8,9], diff = 2
输出:2
解释:
(0, 2, 4) 是算术三元组:8 - 6 == 2 且 6 - 4 == 2 。
(1, 3, 5) 是算术三元组:9 - 7 == 2 且 7 - 5 == 2 。
示例3
输入: words = ["blue","green","bu"]
输出: []
思路
- 本题目采用暴力求解,通过三层循环,寻找符合条件(i < j < k,nums[j] - nums[i] == diff,nums[k] - nums[j] == diff)的三元组。
解法
func arithmeticTriplets(nums []int, diff int) int {
count:=0
for i:=0;i<len(nums);i++{
for j:=i+1;j<len(nums);j++{
for k:=j+1;k<len(nums);k++{
if nums[j]-nums[i]==diff && nums[k]-nums[j]==diff{
count++
continue
}
}
}
}
return count
}
结果
思路
- 相比上述一题的优化点在于:以空间换时间的思想,使用map,省去了三层循环。
解法
func arithmeticTriplets(nums []int, diff int) int {
count:=0
dic:=map[int]bool{}
for i:=0;i<len(nums);i++{
dic[nums[i]]=true
}
for i:=0;i<len(nums);i++{
if dic[nums[i]-diff] && dic[nums[i]+diff]{
count++
}
}
return count
}
结果
6137. 检查数组是否存在有效划分
给你一个下标从 0 开始的整数数组 nums ,你必须将数组划分为一个或多个连续子数组。
如果获得的这些子数组中每个都能满足下述条件 之一 ,则可以称其为数组的一种有效划分:
- 子数组 恰 由 2 个相等元素组成,例如,子数组 [2,2] 。
- 子数组 恰 由 3 个相等元素组成,例如,子数组 [4,4,4] 。
- 子数组 恰 由 3 个连续递增元素组成,并且相邻元素之间的差值为 1 。例如,子数组 [3,4,5] ,但是子数组 [1,3,5] 不符合要求。 如果数组 至少 存在一种有效划分,返回 true ,否则,返回 false 。
示例1
输入:nums = [4,4,4,5,6]
输出:true
解释:数组可以划分成子数组 [4,4] 和 [4,5,6] 。
这是一种有效划分,所以返回 true 。
示例2
输入: nums = [1,1,1,2]
输出: false
解释: 该数组不存在有效划分。
思路
- 自己做这道题的时候,使用的是回溯,但是超时了。。。因此,学习了别人的解法。
- 本题中“划分”说明是存在子问题,那么想到子问题,则一般采用动态规范的方法求解。
- 定义dp[i+1]表示nums[0]到nums[i]这些元素能否被有效划分。
- dp[i+1]=true,如下条件满足一个即可:
- 当i>0,dp[i-1]=true,nums[i-1]=nums[i]
- 当i>1,dp[i-2]=true,nums[i]=nums[i-1],nums[i]=nums[i-2] 或者 nums[i]=nums[i-1]+1,nums[i]=nums[i-2]+1
解法
func validPartition(nums []int) bool {
dp:=make([]bool,len(nums)+1)
dp[0]=true
for i:=0;i<len(nums);i++{
if i>0 && dp[i-1] && nums[i]==nums[i-1] || i>1 && dp[i-2] && ( nums[i]==nums[i-1] && nums[i]==nums[i-2] || nums[i]==nums[i-1]+1 && nums[i]==nums[i-2]+2){
dp[i+1]=true
}
}
return dp[len(nums)]
}
结果
6138. 最长理想子序列
给你一个由小写字母组成的字符串 s ,和一个整数 k 。如果满足下述条件,则可以将字符串 t 视作是理想字符串:
- t 是字符串 s 的一个子序列。
- t 中每两个相邻 字母在字母表中位次的绝对差值小于或等于 k 。 返回最长 理想字符串的长度。
字符串的子序列同样是一个字符串,并且子序列还满足:可以经由其他字符串删除某些字符(也可以不删除)但不改变剩余字符的顺序得到。
注意:字母表顺序不会循环。例如,'a' 和 'z' 在字母表中位次的绝对差值是 25 ,而不是 1 。
示例1
输入:s = "acfgbd", k = 2
输出:4
解释:最长理想字符串是 "acbd" 。该字符串长度为 4 ,所以返回 4 。
注意 "acfgbd" 不是理想字符串,因为 'c' 和 'f' 的字母表位次差值为 3 。
示例2
输入: s = "abcd", k = 3
输出: 4
解释: 最长理想字符串是 "abcd" ,该字符串长度为 4 ,所以返回 4 。
思路
- 本题是字符串类问题,字符串类问题,一般使用枚举的方法。
- 子序列+相邻,一般使用dp方法解决。
- 定义dp[i][c]表示前i个字符里面选一个末尾字符为c的理想字符串的最长长度。
- dp[i][c]=max(dp[i-1][c])+1,其中c的选取范围为[c-k,c+k],当然也在[0,25]的范围内。
- 进一步优化,因为dp[i]从dp[i-1]中选取,因此,可以降维处理,将二维转为一维。
解法
func longestIdealString(s string, k int) int {
dp:=make([]int,26)
for _,c:=range s{ // 字符串问题,需要遍历
c:=int(c-'a') // 将当前字符转为[0,25]中的一个
for j:=max(0,c-k);j<=min(25,c+k);j++{ // c的选取范围为[c-k,c+k],找一个最长的
dp[c]=max(dp[j],dp[c])
}
dp[c]++ // 将c的1进去
}
count:=0
for _,v:=range dp{
count=max(count,v)
}
return count
}
func max(a,b int)int{
if a>b{
return a
}
return b
}