1 条题解

  • 1
    @ 2024-11-19 13:59:46

    使用双指针是降低算法复杂度的一个有效途径,有些问题的暴力解法时间复杂度是O(n^2),但使 用双指针可以大幅度降低算法复杂度。如果面试者能将求解过程从暴力法优化到双指针,说明面试者的基础知识、代码能力、逻辑思维都是十分扎实的。 同贪心算法一样,双指针的难点在于自己想不出、别人的理解不了、正确性难以证明。

    核心思路

    1. 遍历数组a中的每一个元素a[i], 对于每一i,找到j使得双指针[j, i]维护的是以a[i]结尾的最长连续不重复子序列,长度为i - j + 1, 将这一长度与r的较大者更新给r。
    2. 对于每一个i,如何确定j的位置:由于[j, i - 1]是前一步得到的最长连续不重复子序列,所以如果[j, i]中有重复元素,一定是a[i],因此右移j直到a[i]不重复为止(由于[j, i - 1]已经是前一步的最优解,此时j只可能右移以剔除重复元素a[i],不可能左移增加元素,因此,j具有“单调性”、本题可用双指针降低复杂度)。
    3. 用数组s记录子序列a[j ~ i]中各元素出现次数,遍历过程中对于每一个i有四步操作:cin元素a[i] -> 将a[i]出现次数s[a[i]]加1 -> 若a[i]重复则右移j(s[a[j]]要减1) -> 确定j及更新当前长度i - j + 1给r。
    # include <iostream>
    using namespace std;
    #define int long long
    
    const int N = 1e5 + 10,M = 1e7 + 10;
    int a[N], s[M];
    
    signed main()
    {
        int n, r = 0;
        cin >> n;
    
        for (int i = 0, j = 0; i < n; ++ i)
        {
            cin >> a[i];
            ++ s[a[i]];
            while (s[a[i]] > 1) -- s[a[j++]]; // 先减次数后右移
            r = max(r, i - j + 1) ;
        }
        cout << r;
    
        return 0;
    }
    

    信息

    ID
    64
    时间
    1000ms
    内存
    512MiB
    难度
    5
    标签
    (无)
    递交数
    48
    已通过
    20
    上传者