滑动窗口和unordered_set(哈希表)在字符串判断中的应用

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

这个题我一开始用到的是一个很常规的方法(实测我的方法还要优秀一点,无论是时间还是空间),用ascII进行判断,从字符串下标0开始,查询每个下标的最长无重复字符字串,然后取最大值。我把最大值存在ans中,用的一个小技巧是当下标到字符串尾的长度小于ans时,就不需要进行判断了,因为不可能超过ans,节省了一点小时间。
哈希表的方法放在后面讲,

具体代码如下

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
    	//用来判断的字典,其实这里直接写一个={}也可以,但我想用下新学的memset初始化
    	//memset赋值会快一点,
        int adjust[129];
       	//头文件为string,记住这个用法就可以了,(首地址,要赋的值,大小)
        memset(adjust,0,sizeof(adjust));
        int n=s.length(),ans=0;
        int i=0;
        //前面提到的小技巧
       while(i+ans<n)
       {
           int start=i;
           //没有重复的话就向后找
           while(start<n&&adjust[s[start]]!=1)
           {
               adjust[s[start]]++;
               start++;
           }
           //留下最大的
            ans=max(ans,start-i);
            //每次结束之后重置adjust数组
            memset(adjust,0,sizeof(adjust));
            i++;
       }
       return ans;
    }
};

使用哈希表(即散列表)
先大致解释一下哈希表,关于哈希表的详细信息大家可以参考其他的文章(其实我想转载的,但是怕不能不告知转载)大致就是一个使用内存换取查找时间的方法,我上面的那个用于判断的adjust[129]就可以看成一个简单的哈希表(没使用散列函数),但是实际应用中,可能还需要一个散列函数,负责节省空间,即通过一个函数将值映射到内存中,可以减少内存使用。同时由于减少了内存的使用,还需要处理因为函数导致的数据冲突。听起来有点难用

幸运的是stl中有已经写好的哈希表可以使用,这里用到的是unordered_set。
创建方法unordered_set(type) name
插入值name.insert(value)
删除值name.erase(value)
返回值的个数name.count(value)。

判断字符是否出现过的方法已经有了,接下来就是处理技巧滑动窗口。当出现重复的元素时,我们一直将先左边的元素移除,直到表中没有重复的元素,这时表中剩下的元素就都是不重复的元素了,就可以继续查找了
其实我考虑想把滑动窗口应用到第一个方案中,但是写了几次还没写好,就先放一会儿,等以后补上吧

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
    	//建立无序表(功能就是哈希表)
        unordered_set<char> adjust;
        //左值先赋值为-1
        int left=-1,right=0,n=s.length(),ans=0;
        while(right<n)
        {
        	//从左边拆值(未发现重复元素前不许要拆值,即第一次)
            if(left>=0)
            {
                adjust.erase(s[left]);
            }
			
			//未发现重复元素时,从右边放入元素
            while(right<n&&!adjust.count(s[right]))
            {
                adjust.insert(s[right]);
                right++;
            }
            left++;
            ans=max(ans,right-left);
        }
        return ans;
    }
};
  1. 字符串的排列
    给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
    换句话说,s1 的排列之一是 s2 的 子串 。
    示例 1:
    输入:s1 = “ab” s2 = “eidbaooo”
    输出:true
    解释:s2 包含 s1 的排列之一 (“ba”).

计算排列,可能第一个会想到next_permutation。但是这个只需要比较字符串的数量就好了,模板vector可以很方便的比较两个数组相同,所以采用他作为容器。都是小写字母,直接取26,再用s[i]-'a’就可。
在考虑做法,滑动窗口,不符合的时候就将最左边的移除,右边装入一个,只要相等就直接返回true,当右边装入了s2的最后一个元素还没相等的话,直接返回false。

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        int len1=s1.length(),len2=s2.length();
        //当s1比s2长时,显然不包含
        if(len1>len2)
        {
            return false;
        }

        vector<int> adjust(26);
        vector<int> cc2(26);

        for(int i=0;i<len2;i++)
        {
        	//先把s1和与s1等长的s2字符段填入数组adjust和cc2中
            if(i<len1)
            {
                adjust[s1[i]-'a']++;
                cc2[s2[i]-'a']++;
            }else
            {
                if(cc2==adjust)
                    {
                        return true;
                    }

                cc2[s2[i-len1]-'a']--;
                cc2[s2[i]-'a']++;
            }
        }
        
        if(cc2==adjust)
        {
            return true;
        }
        return false;
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
unordered_set和unordered_map是C++11新增加的两个关联式容器,它们的区别主要体现在以下几个方面: 1. 底层实现:unordered_set和unordered_map的底层都是哈希表,而set和map的底层是红黑树。哈希表是一种根据键值直接进行访问的数据结构,而红黑树是一种自平衡的二叉搜索树。 2. 排序:unordered_set是不可排序的,而set是有序的。unordered_map是无序的,而map是有序的。这是因为哈希表是根据键值的哈希值进行存储和访问的,没有固定的顺序。 3. 迭代器:unordered_set和unordered_map使用的是单向迭代器,而set和map使用的是双向迭代器。单向迭代器只能从前往后遍历容器的元素,而双向迭代器可以从前往后和从后往前遍历。 4. 效率:由于底层实现的不同,unordered_set和unordered_map的插入、查找和删除操作的时间复杂度都是O(1),而set和map的时间复杂度是O(logN)。因此,unordered_set和unordered_map相对于set和map来说,在大部分情况下具有更高的效率。 综上所述,unordered_set和unordered_map与set和map在底层实现、排序、迭代器和效率上存在一些区别。选择使用哪个容器取决于具体的需求和性能要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++ 哈希表及unordered_set + unordered_map容器](https://blog.csdn.net/qq_60750110/article/details/126746419)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [算法(42)-数组等值切割-前缀累加和-哈希表Map-set版-C++](https://download.csdn.net/download/weixin_38710566/14039060)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下坠丷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值