关键字:动态规划

归航return:(Trivial) LeetCode 1020—飞地的数量​zhuanlan.zhihu.com

归航return:LeetCode 1316—不同的循环字符串​zhuanlan.zhihu.com

Problem

Given an array A of integers, return the length of the longest arithmetic subsequence in A.

Recall that a subsequence of A is a list A[i_1], A[i_2], ..., A[i_k] with 0 <= i_1 < i_2 < ... < i_k <= A.length - 1, and that a sequence B is arithmetic if B[i+1] - B[i] are all the same value (for 0 <= i < B.length - 1).

Example 1:

Input: [3,6,9,12]
Output: 4
Explanation:
The whole array is an arithmetic sequence with steps of length = 3.

Example 2:

Input: [9,4,7,2,10]
Output: 3
Explanation:
The longest arithmetic subsequence is [4,7,10].

Example 3:

Input: [20,1,15,3,10,5,8]
Output: 4
Explanation:
The longest arithmetic subsequence is [20,15,10,5].

Note:

  1. 2 <= A.length <= 2000
  2. 0 <= A[i] <= 10000

1027. 最长等差数列 - 力扣(LeetCode)​leetcode-cn.com

Solution

这道题目的 tag 是动态规划,既然是 DP,那么最重要的就是确定 base case 和 state transition equation。让我们回顾一下等差数列的性质:一个数列是等差数列,当且仅当数列的长度大于等于 2,而且一阶差分全部相等。此处的一阶差分的长度会比原来的数组长度小 1,而不是 C++ 中的 adjacent_difference 函数。那么既然长度大于等于 2,那么不管等差子序列长度多长,这个等差子序列一定存在最后两项,利用这个就可以建立一个动态规划关系。

定义一个二维的 dp 数组,其中 dp[i][j] 是等差子序列中,最后两项是 nums[i]nums[j] 的情况下,最长的子序列长度,显然,这里自带一个约束,就是 i < j

首先考虑 base case。显然,上述所有的 dp[i][j] ,都必然有 dp[i][j] >= 2。那么什么时候一定取等号呢?显然,当 i == 0 的时候,由于下标最小为 0,我们不可能继续往前延展等差序列,因此 dp[0][j] = 2,其中 1 <= j < nums.length。这是一个非常 well-defined 的 base case。

之后就是考虑状态转移关系。当我们确定了等差数列的最后两项之后,理论上,如果前面还有若干项,而且我们知道项数,那么等差数列就已经被唯一地确定了,因为等差数列有熟知的通项公式

,其中
为公差。所以,如果之前还有若干项,那么等差数列的最后三项一定是等差数列。如果我们能在

nums[i] 之前找到某一项 nums[m],使得 nums[m]nums[i]nums[j] 成等差数列,那么可以将用 nums[m]nums[i] 结尾的等差数列的结尾加上 nums[j],作为 dp[i][j] 的候选。另外,即使找不到,那么 nums[i]nums[j] 本身也可以组成一个长度为 2 的等差数列。综上所述,整个问题的状态转移方程是:

Java 代码如下:

class Solution {public int longestArithSeqLength(int[] A) {if (A.length <= 2){return 2;}if (A.length == 3){return A[2]-A[1] == A[1]-A[0] ? 3 : 2;}int n = A.length;int[][] dp = new int[n][n];//definition: the longest subsequence whose last two nums are A[i] and A[j] with constraint i is less than jfor (int i = 0; i < n; ++i){for (int j = i+1; j < n; ++j){dp[i][j] = 2;//obviously, any subsequence whose length is two is arithmetic//Specially, if the second last num is A[0], there can be no more nums chosen because any access to index less than 0 is illegal}}int res = 2;for (int i = 1; i < n; ++i){for (int j = i+1; j < n; ++j){//compute dp[i][j]for (int m = 0; m < i; ++m){if (A[j]-A[i] == A[i]-A[m]){dp[i][j] = Math.max(dp[i][j], dp[m][i]+1);//If A[j]-A[i] == A[i]-A[m], it means the longest subsequence may be the longest subsequence //whose last two nums are A[m] and A[i], with A[j] appended to the end.}}res = Math.max(dp[i][j], res);}}return res;}
}

这个算法的时间复杂度是 O(n^3),不过题目给出的数据规模是 2K,虽然理论上可能有点悬,但是有惊无险,过了。(经过测试发现,如果输入数组的长度是 2000,则在最后一个 for 循环中需要运算 1331334000 次,这已经超过了通常而言 C++/Java 等语言允许的计算次数上限 10^8 这个数量级了。

一个容易注意到的优化点是,每次查找的时候,我们需要用 O(n)的时间去查找是否有可以连缀成更长的等差数列的情况。然而事实上,如果给定一个长度为 3 的等差数列,其中第一项和第二项分别是 b 和 c,那么第 0 项一定是 a = 2*b-c,这是高中的时候老师说烂了的知识点。

因此不去穷举,而是使用 Hash 表,就可以直接 O(1) 时间就能找到是否能符合要求了。当然,为了能得到 m ,这个 Hash 表应当是 C++ 中的 std::unordered_map,或者 Java 中的 HashMap。C++ 代码如下:

class Solution {public:int longestArithSeqLength(vector<int>& A) {if (A.size() == 2){return 2;}if (A.size() == 3){return A[2]-A[1] == A[1]-A[0];}int n = A.size();vector<vector<int>> dp(n, vector<int>(n, 2));unordered_map<int, vector<int>> cntHashMap;for (int i = 0; i < n; ++i){cntHashMap[A[i]].emplace_back(i);}int res = 2;for (int i = 1; i < n; ++i){for (int j = i+1; j < n; ++j){if (cntHashMap.count(2*A[i]-A[j])){for (const auto m : cntHashMap[2*A[i]-A[j]]){if (m < i){dp[i][j] = max(dp[i][j], dp[m][i]+1);}else{break;}}res = max(res, dp[i][j]);}}}return res;}
};

这个算法打败了 94.39% 的 C++ 提交,可见速度的差异——当然也是和测试用例相关,当数据量增大的时候,Hash 表的优势才能体现出来。

EOF。

最长等差数列_(Trivial) LeetCode 1027—最长等差子序列相关推荐

  1. LeetCode 1027. 最长等差数列

    LeetCode 1027. 最长等差数列 文章目录 LeetCode 1027. 最长等差数列 题目描述 一.解题关键词 二.解题报告 1.思路分析 2.时间复杂度 3.代码示例 2.知识点 总结 ...

  2. LeetCode 1027. 最长等差数列(DP)

    1. 题目 给定一个整数数组 A,返回 A 中最长等差子序列的长度. 回想一下,A 的子序列是列表 A[i_1], A[i_2], ..., A[i_k] 其中 0 <= i_1 < i_ ...

  3. 最长等差数列_最长等差子序列的长度

    问题描述 给定一个整数数组 A,返回A 中最长等差子序列的长度. 输入:[20,1,15,3,10,5,8] 输出:4 解释:最长的等差子序列是 [20,15,10,5] 问题分析 我们要找出最长的等 ...

  4. 最长等差数列_最长等差数列分析

    原题 给定未排序的数组,请给出方法找到最长的等差数列. 分析 题目描述比较简单,但是有一个问题我们需要首先搞清楚:等差数列中的数字,是否要和原始数组中的顺序一致.题目中,并没有说明,这个就需要大家在面 ...

  5. python输出最长字符串_使用Python打印最长的字母子字符串,并打结...

    我将通过以下方式解决该问题: >让我们定义两个字符串:当前字母递增的字符串和当前最长的字符串. >两个字符串都以第一个字母初始化. (这样我们就可以随时阅读他们的最后一封信.) >然 ...

  6. 圆锥曲线万能弦长公式_圆锥曲线的焦点弦长公式

    摘要:本文将以抛物线弦长的几种求法来阐述圆锥曲线的弦长通用求法,并从中感受解析几何创立的必要性,感受不同坐标系作为工具的不同特点及其优缺点. 首先给出一个求解问题. 已知抛物线的焦准距为p(焦准距即焦 ...

  7. android 照片拼接长图_最智能的 Android 长图拼接应用:图片自动连接

    点击「添加」图标,按拼接顺序勾选图片(免费版上限为 5 张),倘若不小心弄错了顺序,无需清除重新添加,可以通过按住图片拖动来进行排列.一切准备妥当之后,下一步就可以点击「连接!」来生成长图了. 生成的 ...

  8. mysql插入长字符串_求助! php mysql insert 长字符串不能插入问题.

    语句是这样的: $sql = "INSERT INTO `{$table->column_list_page}` set nID='{$_REQUEST['NodeID']}',Tit ...

  9. LeetCode 1218. 最长定差子序列(哈希map)

    1. 题目 给你一个整数数组 arr 和一个整数 difference,请你找出 arr 中所有相邻元素之间的差等于给定 difference 的等差子序列,并返回其中最长的等差子序列的长度. 示例 ...

  10. 怎么判断一个字符串的最长回文子串是否在头尾_【Leetcode每日打卡】最长回文串...

    干货预警:所有文章都会首发于我的公众号[甜姨的奇妙冒险],欢迎watch. 一.来历: 力扣从3月开始开启了每日一题打卡活动,于是跟风加入了打卡大军,这两天写评论.发题解,没想到反响还不错,收到了来自 ...

最新文章

  1. 如何写出《黄焖鸡米饭是怎么火起来的》这样的文章
  2. 小白实操ESP8266AT固件烧录,版本1.7.1,希望对爱玩ESP8266的开发小伙伴有帮助!
  3. Aspose.Cells.dll操作exel
  4. 如何修改服务器mac地址,如何修改服务器mac地址
  5. EditPlus常用快捷键
  6. Java中循环删除list中元素的方法总结(总结)
  7. 用脚踹?地震火灾中,如何快速打开人脸识别闸机门?
  8. Vue中使用watch来监听数据变化
  9. Android 接入穿山甲广告
  10. 由syms生成函数,求该函数在某些点的数值
  11. 女性有十大超能力,你知道吗?
  12. 贪婪洞窟2服务器维护,《贪婪洞窟2》停服维护更新内容介绍 24日停机维护更新哪些内容...
  13. 2022-2027年中国电动汽车充电站及充电桩行业市场调研及未来发展趋势预测报告
  14. 苹果支付v2 通知(订阅/退款回调通知)
  15. 集肤效应、邻近效应、边缘效应、涡流损耗
  16. 银行软件测试怎么做的
  17. 我,27岁,程序员,9月无情被辞:想给做开发的提个醒…
  18. ABAP SE54 视图簇
  19. 计算机中存储数据最小的单位是什么,计算机中存储数据的最小单位和存储容量的基本单位各是什么?...
  20. RuntimeError: a leaf Variable that requires grad has been used in an in-place operation

热门文章

  1. mysql xa事务简单实现
  2. jvm系列:Java服务GC参数调优案例
  3. Quick-Cocos2d-x初学者游戏教程(五) --------------------- 辅助工具和跳转场景
  4. 转载:小心别让圆角成了你列表的帧数杀手
  5. 软件测试工程师的工作总结
  6. linux关闭邮件提示错误,LINUX命令关闭 You have mail in /var/spool/mail/root邮件提醒功能...
  7. 编译DPDK遇到make: *** /lib/modules/3.10.0-693.el7.x86_64/build: no such file or dirortory
  8. 遇到的问题:uboot下,关闭串口前需要printf打印一个“UART BUS OFF!!!”提示信息,但是打印不出来
  9. ffmpeg结构体以及函数介绍(二)
  10. P-Associated-URI