NC41 题解 | #最长无重复子数组#

最长无重复子数组

http://www.nowcoder.com/practice/b56799ebfd684fb394bd315e89324fb4

题意分析

  • 给你一个数组,需要找出这个数组里面最长的子序列的长度,要求这个子序列里面的所有的数不重复。
  • 前置知识,首先,你需要了解什么是子序列?
    • 子序列是一个连续的序列,你可以理解为一个数组去掉前面和后面的一部分元素形成的。
    • 然后,你需要了解如何哈希,这里的C++给我们提供了STL,里面的map就是一个很好的用来哈希的容器。
    • 最后,你需要了解双指针,双指针是我们利用两个指针,一个left,一个right,这两个指针根据题目的要求进行移动,我们枚举左指针的起点,然后右指针尽可能往右边走,直到不满足题目的意思的时候。中途我们不断维护最大的值就行了。具体请结合下面的图解理解。

图片说明

  • 上面的图我们可以这样理解,就是我们左边指针始终只移动一步,右边指针多次移动直到不满足条件或者到达边界,然后我们左边指针继续移动,但是在这中途需要我们维护区间的长度的最大值。具体请看下面的思路分析

思路分析

解法一 双指针法

  • 上面我们进行了一些铺垫,我们在了解双指针的用法后就很好解决这个问题了,但是注意这里我们使用unordered_map对每个数字进行哈希,记录每个数字出现的次数。具体请结合相关代码进行理解。

  • 代码如下

    • 需要遍历一遍整个数组,所以时间复杂度为O(n)
    • 用了unordered_map进行了哈希,所以空间复杂度为O(n)
class Solution {
public:
    /**
     * 
     * @param arr int整型vector the array
     * @return int整型
     */
    unordered_map<int,int> mp;
    int maxLength(vector<int>& arr) {
        // write code here
        int len=arr.size();
        int ans=0;
        // 定义两个指针,我们移动右指针
        for(int l=0,r=0;l<len;l++){
            // 如果右指针没有到达边界同时满足题目的条件,那么一致循环下去
            while(l<=r&&r<len&&mp[arr[r]]==0){
                mp[arr[r]]++;
                r++;
            }
            // 因为做指针需要往前移动,所以左边那个数字的个数少1
            mp[arr[l]]--;
            // 维护最大的区间长度
            ans=max(ans,r-l);
        }
        return ans;
    }
};

解法二 双端队列

  • 双端队列就是一个更加实用的队列,普通的队列我们都知道是一端进,一端出的,但是双端队***实两端都可以进出。结合下图

图片说明

  • 直到双端队列的这个性质之后,我们可以进行如下处理,我们用一个unordered_map标记数字出现的次数,然后如果遍历整个数组,如果发现这个数字在队列里面,然后我们不断从队首出队,直到这个数字也出队。然后当前遍历的数字在队尾进行入队操作。中途维护队列的大小的最大值。

  • 代码如下

    • 需要遍历一遍整个数组,所以时间复杂度为O(n)
    • 开了一个deque和unordered_map进行处理,空间复杂度为O(n)
class Solution {
public:
    /**
     * 
     * @param arr int整型vector the array
     * @return int整型
     */
    // 返回两个数字的更大的值
    int Max(int a,int b){
        if(a>b) return a;
        return b;
    }
    int maxLength(vector<int>& arr) {
        // write code here
        deque<int> q; // 定义双端队列
        unordered_map<int,int> mp;  // 用来判断某一个数字是否在队列里面,如果在,那么就是1,否则为0
        int ans=0;
        for(auto x:arr){
            // 如果当前这个数字在队列里面,那么说明存在重复的数字,队首出队
            while(!q.empty()&&mp[x]){
                mp[q.front()]=0; // 将每个出队的数字标记为0
                q.pop_front();
            }
            // 将这个数字从队尾插入
            q.push_back(x);
            mp[x]=1; // 标记
            // 维护最大值
            ans=Max(ans,q.size());
        }
        return ans;
    }
};
全部评论

相关推荐

(黑话警告⚠️:hc=岗位数量,&nbsp;mt=导师,&nbsp;ld=直属领导,&nbsp;cr=代码审查)25年1月,我加入了字节某前端团队,并期望能在这里待到秋招并尝试转正。然而,就在上周,ld&nbsp;找我1v1,告诉我,我的能力和团队预期不太匹配,并和我劝退。晴天霹雳吗?肯定是有的。那一刻,脑子里嗡嗡作响,各种情绪翻涌。但冷静下来想想,这几个月,自己在能掌控的范围内,确实有不少地方做得不尽如人意。所以,我想把这段不算成功的经历复盘一下,希望能给同样在努力转正的你提个醒,避开我踩过的坑。一、ld&nbsp;的要求要注意刚进组时,ld就和我聊过转正的事。我当时发问:“咱们这儿有hc&nbsp;吗?”&nbsp;ld没直接回答,只是说:“看能力,能力到了...
牛客上的彭于晏:过来人告诉你,入职后要做的第一件事儿不是说主动找活儿做,你要先学会融入团队,摸清ld的性格,投其所好。然后才是展示你的能力,能力上可以说技术或者业务,以业务能力为主,技术能力为辅。优先保证自己对业务需求的开发保证质量效率,然后再谈技术的问题,不要你觉得啥啥啥不行就想着整体优化了(发现校招生最喜欢干这事儿),我工作快5年了发现搞这种的最后都没啥好的结果,产出没有还引入新的bug,校招或者实习的水平看到的问题别人看不到嘛?为什么别人不去搞?浪费时间还没收益的事儿不要去做,技术上的能力体现在对于一个新需求,在不符合现在业务发展的架构设计上,你能拿出好的技术方案同时能考虑到后续业务发展逐渐将技术架构引入合理的架构,这是一个漫长的过程而不是一次性的
点赞 评论 收藏
分享
04-12 13:42
江南大学 C++
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务