首页 > 试题广场 >

牛妹的项链

[编程题]牛妹的项链
  • 热度指数:630 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
牛妹收到了一个项链,这个项链一共有n个珠子,每个珠子都有一个颜色a_i。这n个珠子构成了一个环。

不知为何,牛妹想从项链上截下一段连续的珠子,但是牛妹不喜欢同一个颜色出现两次,所以截下来的这一段珠子中没有相同的颜色。现在牛妹想知道她可以截下的最长的一段珠子为多长?

个珠子与第个珠子和第个珠子相邻。(i>1且i<n)
特别的,与第1个珠子相邻的珠子为第2个,第n个珠子。
与第n个珠子相邻的珠子为第n-1个,第1个珠子。
示例1

输入

4,[3,1,1,2]

输出

3

说明

牛妹可以选择在第3个珠子的左边和右边各切一刀,截取第4个,第1个和第2个珠子连起来的连续珠子。

备注:

第一个参数n代表珠子个数
第二个参数vector<int> a包含n个元素代表每个珠子的颜色。
#include <unordered_map>
class Solution {
public:
    /**
     * 牛妹的项链
     * @param n int整型 
     * @param a int整型vector 
     * @return int整型
     */
    int solve(int n, vector<int>& a) {
        unordered_map<int, int> M;
        int s=0, k=0;
        for(int i=0;i<(n<<1);i++){
            if(M.find(a[i%n]) != M.end()){
                k = max(k, M[a[i%n]]);
                s = max(s, i-k);
            }
            M[a[i%n]] = i;
        }
        return s;
    }
};

编辑于 2020-07-26 00:58:26 回复(0)
class Solution {
public:
    /**
     * 牛妹的项链
     * @param n int整型 
     * @param a int整型vector 
     * @return int整型
     */
    int solve(int n, vector<int>& a) {
        map<int, int> Map;
        int l = n, Max = 1;
        for (int r = n; r < 2 * n; r++) {
            a.push_back(a[r - n]);
            if (r == n) while (Map.find(a[l]) == Map.end()) {Map[a[l]] = l; l--;}
            else {
                if (Map.find(a[r]) != Map.end()) l = max(l, Map[a[r]]);
                Map[a[r]] = r;
            }
            Max = max(Max, r - l);
        }
        return Max;
    }
};

发表于 2020-07-29 14:23:12 回复(0)
动态规划,使用dp记录每一个位置可以截取的最大长度,使用ind记录没有颜色重复的初始位置
class Solution:
    def solve(self, n, a):
        dp = [0] * n  # 记录每个位置的最大值
        dp[0] = 1  # 第一个位置初始值为1
        ind = 0  # 记录没有颜色重复的初始位置,初始值为0
        for i in range(1, n):  # 从第二个位置开始更新dp
            if a[i] in a[ind:i]:  # 第i个颜色是否为重复颜色
                c = a[ind:i]  # 将没有颜色重复的这一段截取出来
                c.reverse()  # 反转,为了下一步得到和第i个颜色重复的珠子的位置
                ind += (len(c) - 1) - c.index(a[i])  
                # ind加上 和第i个颜色重复的珠子在没有颜色重复区间的位置,得到和第i个颜色重复的珠子在整串珠子中的位置
                dp[i] = i - ind  # 得到dp[i]
                ind += 1  # 更新没有颜色重复的初始位置
            else:  # 第i个颜色没有重复时
                dp[i] = i + 1 - ind  
                
        # 考虑将首位两端连接的情况
        aa = a[-dp[-1]:]  # 截取最后一个位置能得到的最大长度,在考虑从第一个开始往后的颜色有无重复即可
        j = 0
        while a[j] not in aa:  # 没有重复,将dp[i]加一即可,有重复就停止
            dp[-1] += 1
            j += 1
        return max(dp)  # 返回dp[i]的最大值,即最大的长度


发表于 2020-07-09 16:24:09 回复(0)
动态规划。先不管环,只计算单向的最长序列,然后判断首尾相连的情况。
int solve(int n, vector<int>& a) {
        // write code here
        vector<int> dp(n+1, 0); // dp[i]表示以第i个珠子结尾的最长单色长度
         
        dp[1]=1;
        int res=0;
        for(int i=2;i<=n;i++){ // 单向遍历搜索,以i结尾的最长长度
            int pre=i-1;
            for(; pre>i-1-dp[i-1] && a[pre-1]!=a[i-1];pre--){ // 判断前dp[i-1]个珠子是否和第i个珠子同色, 同色就停下
            }
            dp[i]=i-pre; // 第i个珠子结尾的最长长度
            res=max(res, dp[i]);
        }
         
        int i=1;
        // 还没有判断首尾相连的情况,所以遍历首部的几个珠子。
        // 符合条件的是,前i个珠子都不同色(若存在同色,则不用继续向后了),并且不在尾部的那个序列中
        for(;i>=dp[i] && i<n-dp[n];i++){ 
            int j=n;
            for(;j>n-dp[n] && a[i-1]!=a[j-1];j--){ // 判断第i个珠子是否和尾部的珠子同色
            }
            if(j>n-dp[n]){
                i++;
                break;
            }
        }
        res=max(res, dp[n]+i-1); // i是首部符合条件的后一个,所以减1
         
        return res;
    }


发表于 2020-04-28 20:37:41 回复(0)
int solve(int n, vector<int>& a) {
    map<int, int> mm;
    int ret = 0;
    int last = 0;
    for(int i = 0; i < n * 2; i++){
        auto itr = mm.find(a[i%n]);
        if(itr != mm.end()){
            last = max(last, itr->second);
            ret = max(ret, i - last);
        }
        mm[a[i%n]] = i;
    }
    return ret;
}
每个位置作为结尾,找到构成最长的起始位置last, last应该保证不能有元素重复,mm保留每个值最后出现位置
发表于 2020-04-22 11:04:42 回复(0)

问题信息

难度:
5条回答 2451浏览

热门推荐

通过挑战的用户

查看代码