1218. 最长定差子序列

1 题目理解

给你一个整数数组 arr 和一个整数 difference,请你找出并返回 arr 中最长等差子序列的长度,该子序列中相邻元素之间的差等于 difference 。
输入:整数数组arr, 整数difference
输出:最长等差子序列的长度
规则:这个等差子序列相邻元素的差等于difference
示例 1:
输入:arr = [1,2,3,4], difference = 1
输出:4
解释:最长的等差子序列是 [1,2,3,4]。

示例 2:
输入:arr = [1,3,5,7], difference = 1
输出:1
解释:最长的等差子序列是任意单个元素。

示例 3:
输入:arr = [1,5,7,8,5,3,4,2,1], difference = -2
输出:4
解释:最长的等差子序列是 [7,5,3,1]。

2 开始思考

以arr = [1,5,7,8,5,3,4,2,1], difference = -2 为例。
处理1,子序列是[1]
处理5,因为5-1!=-1,所以产生子序列[5],此时子序列有[1],[5]
处理7,因为7-5!=-2,7-1!=-2,所以产生子序列[7],此时子序列有[1],[5],[7]
处理8…,此时子序列有[1],[5],[7],[8]
处理5,因为5-8!=-2,5-7=-2,子序列变为:[1],[5],[7,5],[8]

所以发现,在处理每一个数的时候,和他前面已经形成的每个子序列的某位数字比较,符合条件就可以追加,不符合条件就单独成一个子序列。当然在追加的时候肯定要选择追加在最长的那个子序列后面。
当一个数追加到子序列之后,后面的处理就只与这个数有关系,而与子序列的具体序列无关,所以可以使用dp。
用dp[i]表示以arr[i]结尾的等差子序列的最长长度。最后结果在dp[0],dp[1]…dp[n-1]之间选择最大的。

class Solution {
    public int longestSubsequence(int[] arr, int difference) {
        int n = arr.length;
        int[] dp = new int[n];
        dp[0] = 1;
        int max = 1;
        for(int i=1;i<n;i++){
            dp[i] = 1;
            for(int j=0;j<i;j++){
                if(arr[j] + difference == arr[i]){
                    dp[i] = Math.max(dp[i],1+dp[j]);
                }
            }
            max = Math.max(max,dp[i]);
        }
        return max;
    }
}

提交之后发现超时。再一思考。当处理arr[i]的时候,它等差子序列的前一个数值是确定的,一定是arr[i]-difference。也就是说,不需要关心从0到i-1,每个子序列的最长长度,只要关心以arr[i]-difference为结尾的等差子序列的长度即可。

class Solution {
    public int longestSubsequence(int[] arr, int difference) {
        int n = arr.length;
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        int[] dp = new int[n];
        dp[0] = 1;
        map.put(arr[0],1);
        int max = 1;
        for(int i=1;i<n;i++){
            dp[i] = 1;
            int t = arr[i] - difference;
            if(map.containsKey(t)){
                dp[i] = Math.max(dp[i],map.get(t)+1);
            }
            map.put(arr[i],dp[i]);
            max = Math.max(max,dp[i]);
        }
        return max;
    }
}

在做315 Count of Smaller Numbers After Self的时候,因为没有考虑重复元素使用map,出错了。所以现在有点犹豫,可以这样吗?当数值重复的时候会出错吗?

还是上面的例子:[1],[5],[7,5],[8],当处理数字3的时候,3-(-2)=5,当然追加在[7,5]后面变成[7,5,3]。我们从左到右处理,当map中有5的长度的时候,5一定出现在3前面,但是至于是什么位置的5并不关心,也没有关系。因为子序列就不一定是连续的。
再从另外一个角度考虑。如果 arr[i-3] arr[i-1] arr[i] 是一个等差序列,
那么当 arr[j]=arr[i],并且 j>i的时候,那么 arr[i-3] arr[i-1] arr[j] 也一定是一个等差序列。而且 在i到j之间,可能产生一个更长的等差序列数组。
所以map优化,以arr[i]为key没有问题。

猜你喜欢

转载自blog.csdn.net/flying_all/article/details/111879061