思路:

题目的主要信息:

  • 用数组a表示项链的不同颜色,即不同数字表示不同颜色,且首尾相接
  • 从数组中取出一段数字都不同的连续子序列,求子序列最长长度,需要注意首尾相接的情况

方法一:动态规划
具体做法:
我们可以将数组首尾相接,组成一个的新数组,就不需要再处理循环了。我们用表示以第个珠子结尾的最长连续不相同颜色的长度,遍历新数组,每次判断判断前个珠子是否和第个珠子同色,同色则停下,然后记录下最长长度。
图片说明

class Solution {
public:
    int solve(int n, vector<int>& a) {
        int res = 0;
        for(int i = 0; i < n; i++) //首尾相接
            a.push_back(a[i]);
        vector<int> dp(2 * n + 1, 0);//dp[i]表示以第i个珠子结尾的最长连续不相同颜色的长度
        dp[1] = 1;
        for(int i = 2; i <= 2 * n; i++){
            int j;
            // 判断前i-1个珠子是否和第i个珠子同色,同色则停下
            for(j = i - 1; j > i - 1 - dp[i - 1] && a[j - 1] != a[i - 1]; j--);
            dp[i] = i - j; //以第i个珠子结尾的最长连续不相同颜色的长度
            res = max(res, dp[i]);  
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,两层循环,每层都是
  • 空间复杂度:,辅助数组dp的长度

方法二:哈希表
具体做法:
因为子序列中元素有互异性,我们可以想到用哈希表来查重。因为数组首尾相接是循环,我们可以考虑遍历长度为2倍数组长度,然后取模。遍历的时候,如果遇到一个数字在哈希表中出现过,我们可以比较它最后出现的位置,将现在的位置减去最后出现的作为一次连续子序列的长度,不断维护最大值。同时,每次遇到一个元素之后,需要用哈希表记录其最后一次出现的位置。

class Solution {
public:
    int solve(int n, vector<int>& a) {
        unordered_map<int, int> mp;
        int res = 0;
        int last = 0; //最长子序列的起始位置
        for(int i = 0; i < 2 * n; i++){
            if(mp.find(a[i % n]) != mp.end()){
                last = max(last, mp[a[i % n]]); //找到它最后出现的位置
                res = max(res, i - last); //维护最大值
            }
            mp[a[i % n]] = i;  //记录每个值最后出现的位置
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,一次遍历,循环长度为
  • 空间复杂度:,最坏情况下所有元素都不同,哈希表最大