LeetCode493周赛T3,前后缀分解

给你一个整数数组 nums。

如果子数组中相邻元素的差值是一个常数,那么这个子数组被称为 等差子数组。

你可以将 nums 中的 最多 一个元素替换为任意一个 整数。然后,从 nums 中选择一个等差子数组。

返回一个整数,该整数表示你可以选择的 最长 等差子数组的长度。

子数组 是数组中一段连续的元素序列。

示例 1:

输入: nums = 9,7,5,10,1

输出: 5

解释:

将 nums3 = 10 替换为 3,数组变为 9, 7, 5, 3, 1。

选择子数组 9, 7, 5, 3, 1,它是等差数组,相邻元素的公差为 -2。

示例 2:

输入: nums = 1,2,6,7

输出: 3

解释:

将 nums0 = 1 替换为 -2,数组变为 -2, 2, 6, 7。

选择子数组 -2, 2, 6, 7,它是等差数组,相邻元素的公差为 4。

提示:

4 <= nums.length <= 105

1 <= numsi <= 105

前后缀分解

  1. 可以在O(n)复杂度内计算出最长的等差长度
  2. 然后枚举每一个元素是否需要更改,更改了以后对前后序列的影响
  3. 一定要明白定义数组的含义,这题解法有好几个写法,原理不难,但是不同解法对应的下标不同,容易绕晕,我定义pre[i]表示以nums[i]为结尾的等差序列的最大长度,这是从前往后 算的;suf[i]表示以nums[i]结尾的等差序列的长度,是从后往前算的
java 复制代码
class Solution {
    public int longestArithmetic(int[] nums) {
        int n = nums.length;
//        pre[i] 表示 nums[0..i] 中最长等差数列的长度
        int[] pre = new int[n];
        pre[0] = 1;
        pre[1] = 2;
        for (int i = 2; i < n; i++) {
            if (nums[i] - nums[i-1] == nums[i - 1] - nums[i - 2]) {
                pre[i] = pre[i - 1] + 1;
            } else {
                pre[i] = 2;
            }
        }
//        suf[i]表示 nums[i..n-1] 中最长等差数列的长度
        int[] suf = new int[n];
        suf[n-1] = 1;
        suf[n-2] = 2;
        for (int i = n-3; i >= 0; i --) {
            if (nums[i] - nums[i+1] == nums[i + 1] - nums[i + 2]) {
                suf[i] = suf[i + 1] + 1;
            } else {
                suf[i] = 2;
            }
        }
        int ans = 0;
        for (int x : pre) {
            ans = Math.max(ans, x);
        }
//        这里ans + 1为了处理更改的元素为端点
        ans ++;

        if (ans >= n) { // 整个数组是等差的,或者修改端点元素后是等差的
            return n;
        }
        for (int i = 1; i < n - 1; i++) {
            // 把 nums[i] 改成 d2 / 2
            int d2 = nums[i + 1] - nums[i - 1];
            if (d2 % 2 != 0) { // d2 / 2 必须是整数
                continue;
            }
//            如果修改过的元素与之前的元素是等差的
            boolean okLeft = i > 1 && nums[i - 1] - nums[i - 2] == d2 / 2;
            boolean okRight = i + 2 < n && nums[i + 2] - nums[i + 1] == d2 / 2;

//           suf[i+1]表示 nums[i+1..n-1] 中最长等差数列的长度
            if (okLeft && okRight) {
                ans = Math.max(ans, pre[i - 1] + 1 + suf[i + 1]);
            } else if (okLeft) {
//                +2 表示修改后的序列多加了nums[i].nums[i+1]
                ans = Math.max(ans, pre[i - 1] + 2);
            } else if (okRight) {
                ans = Math.max(ans, suf[i + 1] + 2);
            }
        }

        return ans;
    }



}
相关推荐
码爸8 小时前
线性回归算法
算法·机器学习·线性回归
Coder-magician9 小时前
《代码随想录》刷题打卡day51:图论-part09(dijistra堆优化,Bellman_ford算法)
算法·图论
Nil2089 小时前
leetcode 763划分字母区间
算法·leetcode·职场和发展
不会就选b9 小时前
算法日常・每日刷题--<动态规划>20
算法·leetcode·动态规划
青少儿编程课堂10 小时前
迪杰斯特拉(Dijkstra)算法:单源最短路与赛场路线规划
c++·python·算法·bfs·信息学竞赛
不会就选b10 小时前
算法日常・每日刷题--<动态规划>19
算法·leetcode·职场和发展
没有钱的钱仔12 小时前
协方差矩阵含义
算法·机器学习·矩阵
垆边人似月.12 小时前
华为机试题 :和为 K 的子数组个数
算法·leetcode·华为
三*一12 小时前
优化修整算法
前端·javascript·算法