给你一个整数数组 arr
和一个整数 difference
,请你找出并返回 arr
中最长等差子序列的长度,该子序列中相邻元素之间的差等于 difference
。
子序列 是指在不改变其余元素顺序的情况下,通过删除一些元素或不删除任何元素而从 arr
派生出来的序列。
这道题,看了一眼,劈里啪啦一分钟写完,自信写完,时间超限,天杀的我就知道我不可能一分钟做出mid题!!
/**
* @param {number[]} arr
* @param {number} difference
* @return {number}
*/
var longestSubsequence = function(arr, difference) {
const n=arr.length;
const dp=new Array(n+1).fill(1);
let res=0;
for(var i=0;i<n;i++){
for(var j=0;j<i;j++){
if(arr[i]-arr[j]==difference){
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
if(res<dp[i])res=dp[i];
}
return res;
};
没关系,我们来理思路,这至少说明前面几道题我能做到看见即秒了。
其实我们思路基本上是对的,但是得利用一点巧思。
看官方给的思路。
因为我们每次都在左侧找一个最近的等于arr【i】-d元素并取其对应dp值。
因此我们直接用dp【v】表示以v为结尾的最长的等差子序列的长度
官方题解使用了动态规划的方法来解决这个问题,并且为了优化空间复杂度,采用了哈希表(在 JavaScript 中是
官方题解使用了动态规划的方法来解决这个问题,并且为了优化空间复杂度,采用了哈希表(在 JavaScript 中是 Map 对象)来存储中间结果。这种方法的关键是理解状态转移方程和如何利用哈希表来高效地实现这个方程。
在这个问题中,状态转移方程是 `dp[v] = dp[v-d] + 1`,意味着如果存在一个值为 `v-d` 的元素,那么以值为 `v` 的元素结尾的最长等差子序列的长度可以从以 `v-d` 结尾的最长等差子序列的长度推导出来,即在后者基础上加一。
解题步骤
1. 初始化:创建一个 Map 对象 `dp` 来存储每个值作为等差子序列末尾时的最长长度。同时,初始化一个变量 `ans` 来记录遍历过程中找到的最长等差子序列的长度。
2. 遍历数组:遍历给定数组 `arr` 中的每个元素 `v`。
3. 更新 DP 表:对于当前元素 `v`,查找 `dp` 中 `v-difference`(即 `v-d`)的值。如果找到了,说明存在一个等差子序列以 `v-d` 结尾,那么以 `v` 结尾的最长等差子序列的长度就是以 `v-d` 结尾的最长等差子序列的长度加一。如果没有找到,说明以 `v` 为结尾的等差子序列只包含 `v` 本身,其长度为1(这里通过 `(dp.get(v - difference) || 0) + 1` 实现,如果 `dp.get(v - difference)` 返回 `undefined`,则用 `0` 替代)。
为了更好理解 也可以替换成
if(dp.get(v - difference) ==undefined){ dp.set(v,1) }else{ dp.set(v,dp.get(v - difference)+1) }
4. 更新最大长度:每次更新 `dp[v]` 后,用 `dp.get(v)` 更新 `ans`,确保 `ans` 始终是遍历到目前为止找到的最长等差子序列的长度。
5. 返回结果:遍历结束后,`ans` 存储的就是整个数组的最长等差子序列的长度。
var longestSubsequence = function(arr, difference) {
let ans = 0;
const dp = new Map();
for (const v of arr) {
dp.set(v, (dp.get(v - difference) || 0) + 1);
ans = Math.max(ans, dp.get(v));
}
return ans;
};
这段代码实现了上述逻辑:
- 使用 `for (const v of arr)` 遍历数组。
- 对每个元素 `v`,通过 `dp.set(v, (dp.get(v - difference) || 0) + 1);` 更新哈希表,这里 `dp.get(v - difference) || 0` 是获取以 `v-difference` 结尾的最长等差子序列的长度,如果不存在则返回0,然后加1表示将当前元素 `v` 加入到等差子序列中。
- 使用 `ans = Math.max(ans, dp.get(v));` 更新找到的最长等差子序列的长度。
- 最终返回 `ans` 作为结果。
如果想把过程写的更加清晰一点就: