等差数列划分--子序列问题DP解决
Posted C_YCBX Py_YYDS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了等差数列划分--子序列问题DP解决相关的知识,希望对你有一定的参考价值。
题目
暴力回溯构建等差数组+数学方法优化
当出现完全一样元素大小的长度很长的数组数组时,可计算Cn1…Cnn来实现。
超时,差最后一个case
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
using ll = long long;
int n = nums.size();
if(n<3)return 0;
auto check = [&](){
int b = nums[0];
for(auto t:nums){
if(b!=t)
return false;
}
return true;
};
if(check()){
ll res = 1<<n;
//减去Cn1-Cn2-Cn0
res -= n;
res -= n*(n-1)/2;
res -= 1;
return res;
}
int cnt = 0;
//backtrack维护一个等差数组
function<void(vector<ll>&,int)> backtrack = [&](vector<ll>&t,int pos){
if(t.size()>2)
cnt++;
for(int i=pos;i<n;i++){
if(t.size()<2){
t.emplace_back(nums[i]);
backtrack(t,i+1);
t.pop_back();
}else{
int sz = t.size();
ll gap = t[sz-1] - t[sz-2];
if(gap==(ll)nums[i]-t[sz-1]){
t.emplace_back(nums[i]);
backtrack(t,i+1);
t.pop_back();
}
}
}
};
vector<ll>q;
backtrack(q,0);
return cnt;
}
};
以等差数列的最后两元素为状态dp
dp[i][j]
表示以 i 和 j 下标对应最后两元素的等差数列个数,所以存在转移关系:dp[i][j] += dp[j][k]+1,(k<j<i)
;
而k是怎么来的呢?
nums[j] - nums[k] = nums[i] - nums[j]
=>nums[k] = 2*nums[j]-nums[i]
一旦存在这样的下标 k 便可进行状态转移
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
using ll = long long;
int n = nums.size();
if(n<3)return 0;
unordered_map<ll,vector<int>>check;
//记录值对应的下标,由于存在重复,所以用数组存
for(int i=0;i<nums.size();i++){
check[nums[i]].emplace_back(i);
}
int dp[n][n];
int res = 0;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
ll target = (ll)2*nums[j]-nums[i];
vector<int>& t = check[target];
for(auto&& k:t){
if(k<j)
dp[i][j] += (dp[j][k]+1);
}
res += dp[i][j];
}
}
return res;
}
};
以上是关于等差数列划分--子序列问题DP解决的主要内容,如果未能解决你的问题,请参考以下文章
leetcode打卡——等差数列题目(LIS变式)——1218. 最长定差子序列
LeetCode 446 等差数列划分II - 子序列[动态规划] HERODING的LeetCode之路
LeetCode 446. 等差数列划分 II - 子序列(动态规划)/ 416. 分割等和子集 (背包问题)/322. 零钱兑换(完全背包)
2022-02-06:等差数列划分 II - 子序列。 给你一个整数数组 nums ,返回 nums 中所有 等差子序列 的数目。 如果一个序列中 至少有三个元素 ,并且任意两个相邻元素之差相同,则称