冉宝的每日一题--8月11日

本文介绍了LeetCode第446题《等差数列划分 II - 子序列》的解题思路。作者分享了尝试解决该困难级别问题的过程,包括寻找最长等差子序列、避免重复计算的方法,并讨论了可能的动态规划解决方案。最后,作者反思了长时间思考题目是否值得,并决定直接参考答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天看了电视剧《我在他乡挺好的》大结局,三个小时,就没有时间写leetcode了,就当作休息啦
今天继续~
最近天天在公司写模型,但是今天好像收敛的没有那么理想,明天再研究一下。
注意和pcgg代码的兼容性呀

先是每日一题吧
居然是个困难题,看见难度级别就觉得没戏了,只争取部分用例通过吧。

446. 等差数列划分 II - 子序列

题目描述

https://leetcode-cn.com/problems/arithmetic-slices-ii-subsequence/

给你一个整数数组 nums ,返回 nums 中所有 等差子序列 的数目。

如果一个序列中 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该序列为等差序列。

例如,[1, 3, 5, 7, 9]、[7, 7, 7, 7] 和 [3, -1, -5, -9] 都是等差序列。
再例如,[1, 1, 2, 5, 7] 不是等差序列。
数组中的子序列是从数组中删除一些元素(也可能不删除)得到的一个序列

例如,[2,5,10] 是 [1,2,1,2,4,1,5,10] 的一个子序列。
题目数据保证答案是一个 32-bit 整数。

示例 1:

输入:nums = [2,4,6,8,10]
输出:7
解释:所有的等差子序列为:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]

示例 2:

输入:nums = [7,7,7,7,7]
输出:16
解释:数组中的任意子序列都是等差子序列。

提示:
1 < = n u m s . l e n g t h < = 1000 1 <= nums.length <= 1000 1<=nums.length<=1000
− 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 231<=nums[i]<=2311

思路:

用时:23:33-
思路:
首先想到的是:
(1) 找到最长的等差子序列,然后每个部分也是等差

  1. 等差 > 0或 <0的时候
    如示例1:[2,4,6,8,10] 长度为:len_max
    这个玩意长度为5,差为2 = => 同样差为2的子序列有 长度为3 的 3个,长度为4 的 2个。
    即: (1 + len_max - 2) * (len_max -2 )/2 ==> (len_max-1)(len_max-2) /2

– 为了避免重复,所以这种改进为:每次固定前两个,后面的长度随意长
所以这种是:len_max - 2
– 其他的可以

  1. 等差等于=0的时候
    [7,7,7,7,7] 子序列的数量就是等差子序列的数量。
    子序列的数量为 每个位选择要或者不要 $2^n $
  • 长度<3的子序列数量 ( n 0 ) {n\choose 0} (0n) + ( n 1 ) {n\choose 1} (1n) + ( n 2 ) {n\choose 2} (2n)
    长度为0 的子序列数量 1
    长度为1的子序列数量 n
    长度为2的子序列数量 n(n-1)/2
    = 2^n - (1 + n +n(n-1)/2 )
fun = lambda n:int(pow(2,n) - (1 + n + n*(n-1)/2 ))

(2)如何找到最长的等差子数列
看数组长度为1000,感觉复杂度 o ( n 3 ) o(n^3) o(n3) 已经是极限了。
算法:
len_nums = len(nums)
有一个大的map存储每个元素
num_dict:
其中:num_dict[num] = [] numindex的list,顺次加的
1- 指针1 :index1 从:0–>len_nums-3
指针2: index2 从 index1 -> len_nums-2
然后gap就确定了:
gap = nums[index2]-nums[index1]
new_num = nums[index2] + gap
2分查找最小的index,再找下一个元素。
直到找不到break。 记下这一组。
可能存在的问题:

  • [2,4,4,6,8,10] --> 所有的都计算,会出现重复的。-- 那就固定前两个。固定前两个的

还有可能是个动态规划的题目,因为答案无后置性。
新增加一个数:
1- 原来的等差数列长度+1
1- 原来的等差数列长度不变,最后一个位换了
2- 构成新的等差数列

1000 * 1000 的矩阵也不是很大

这样的思路做的话
dp[i][j] = 以 nums[i] 结尾,上一个元素是nums[j]的 等差数列 的差和序列长度。

然后现在已经一点半了,我真的无比后悔花了两个小时想这个题。
–以后我再超过一个小时想题目,我就是猪。
直接抄答案不好么
尾项和公差可以确定一个等差数列,定义状态 f [ i ] [ d ] f[i][d] f[i][d] 表示尾项为 n u m s [ i ] nums[i] nums[i] ,公差为 d d d 的弱等差子序列的个数。

# 子序列基本都可以用二维动态数组
from  typing import List
from collections import defaultdict
class Solution:
    def numberOfArithmeticSlices(self, nums: List[int]) -> int:
        res = 0
        len_nums = len(nums)
        if len_nums<3: return 0
        dp = [[0 for i in range(len_nums)] for i in range(len_nums)]
        # dp[i][j] 以nums[i] 结束,上一个元素为 nums[j] 的等差序列【长度为2】的种数
        # 对角线为1
        for i in range(len_nums):
            if i >0:
                dp[i][0] = 0.5 # 第一列都是2

        num_dict = defaultdict(list)
        for ind,num in enumerate(nums):
            num_dict[num].append(ind)
        # print(num_dict)

        # 开始计算
        for i in range(2,len_nums):
            for j in range(1,i):
                # print(dp)
                gap = int(nums[i] - nums[j])
                # 再上一个元素应该为:nums[j] -gap
                last_ele = int(nums[j] -gap)
                # print("last_ele:",last_ele)
                if last_ele not in num_dict:
                    dp[i][j] = 0.5
                    continue

                # 找到所有位置
                last_ele_index = []
                for last_ele_ind in num_dict[last_ele]:
                    if last_ele_ind < j:
                        last_ele_index.append(last_ele_ind)
                if not last_ele_index:
                    dp[i][j] = 0.5
                    continue
                tmp_ = 0
                for last_ele_ind in last_ele_index:
                    if dp[j][last_ele_ind]>0.1 and dp[j][last_ele_ind] < 1:
                        tmp_ += 1
                    else:
                        tmp_ += dp[j][last_ele_ind]+1
                    
                dp[i][j] = tmp_
                # 然后更新结果
                res+=  dp[i][j]
        return res

终于,我还是做出来了,洗个澡睡觉啦,希望明天工作顺利~
请添加图片描述
– 主要需要思考的就是更新策略:
如果前面的长度为2,就直接累加,前面的长度已经大于=3了,就相当于新增了一个。

for last_ele_ind in last_ele_index:
    if dp[j][last_ele_ind]>0.1 and dp[j][last_ele_ind] < 1:
        tmp_ += 1
    else:
        tmp_ += dp[j][last_ele_ind]+1

晚安啦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值