当前位置: 首页 > article >正文

【每日刷题】Day106

【每日刷题】Day106

🥕个人主页:开敲🍉

🔥所属专栏:每日刷题🍍

🌼文章目录🌼

1. LCR 015. 找到字符串中所有字母异位词 - 力扣(LeetCode)

2. 30. 串联所有单词的子串 - 力扣(LeetCode)

3. 69. x 的平方根 - 力扣(LeetCode)

1. LCR 015. 找到字符串中所有字母异位词 - 力扣(LeetCode)

//思路一:无优化版滑动窗口+哈希。非常慢。

class Solution {

public:

    vector<int> findAnagrams(string s, string p)

    {

        vector<int> ans;

        int hash[127] = {0};

        int i = 0,j = 0,psize = p.size();//psize用于判断是否找到了异位词

//记录p中出现的字母及个数

        for(int n = 0;n<p.size();n++)

        {

            hash[p[n]] += 1;

        }

        while(s.size()-i>=p.size()&&j<s.size())

        {

//如果s中当前字母在p中出现,继续遍历

            if(hash[s[j]])

            {

                hash[s[j]]--;

                j++;

                psize--;

            }

//找到异位词的情况

            else if(!hash[s[j]]&&!psize)

            {

                ans.push_back(i);

//重置哈希表

                for(int n = 0;n<p.size();n++)

                {

                    hash[p[n]] += 1;

                }

                psize = p.size();

                i++;

                while(i<s.size()&&!hash[s[i]]) i++;

                j = i;

            }

//没找到异位词的情况

            else

            {

                for(int x = 0;x<127;x++)

                {

                    if(hash[x]) hash[x] = 0;

                }

                for(int n = 0;n<p.size();n++) hash[p[n]] += 1;

//这里相当于O(N^2)的时间复杂度了

                j = ++i;

                psize = p.size();

            }

        }

        if(!psize) ans.push_back(i);

        return ans;

    }

};

//思路二:优化版滑动窗口+哈希。非常快

//我们利用两个哈希表,hash1和hash2,来比较两个字串是否相同,再使用一个变量psize用于记录字符串p的长度。

//hash1初始记录p中出现的字母及个数,后续操作不需要改变hash1

//hash2初始记录s中前psize个字母及个数,后续需要不断改变hash2,具体如何改变,看图:

class Solution {

public:

    vector<int> findAnagrams(string s, string p)

    {

        vector<int> ans;

        int hash1[127] = {0};

        int hash2[127] = {0};

//hash1记录p中所有字母及每个字母的个数

        for(int n = 0;n<p.size();n++) hash1[p[n]]++;

        int i = 0,j = p.size()-1;

//hash2初始记录s中前psize个字母及每个字母的个数,后续会不断改变

        for(int m = 0;m<=j;m++) hash2[s[m]]++;

        while(s.size()-i>=p.size())

        {

//通过判断hash1内存是否与hash2相同来判断是否找到了异位词

            if(memcmp(hash1,hash2,sizeof(int)*127)==0) ans.push_back(i);

//窗口滑动

            hash2[s[i++]]--;

            hash2[s[++j]]++;

        }

        return ans;

    }

};

2. 30. 串联所有单词的子串 - 力扣(LeetCode)

//思路:滑动窗口+哈希表容器。

//本题还是很难的,不过思路并不是难点,难点在于细节的处理上,本题的思路与上面那一题是一样的,只不过滑动窗口维护的对象从单个字母变成多个字母。

//先来画图看一下本题的思路:

//但是如何将多个字母看作为一个字母呢?这里我们需要借助unordered_map这个容器,这个容器可以帮助我们计算字符串出现的频次

//当到这一步后,我们就可以着手开始写代码了

class Solution {

public:

    vector<int> findSubstring(string s, vector<string>& words)

    {

        vector<int> ans;

//借助容器,记录words中字符串出现的频次

        unordered_map <string,int> hash1;

        for(auto& s : words) hash1[s]++;

//获取words每个字符串的长度,以及words的长度,后面有用

        int len = words[0].size(),size = words.size();

//这一步就是细节上的处理了,因为我们不一定是在字符串的开头就找到字串,因此我们需要遍历len次,就能确保每一个可能出现字串的位置都找一遍

        for(int i = 0;i<len;i++)

        {

//hash2用于记录s中当前字符串出现的频次

            unordered_map <string,int> hash2;

            for(int left = i,right = i,count = 0;right+len<=s.size();right+=len)

            {

//in用于获取s中当前字符串,长度与len一致

                string in = s.substr(right,len);

//记录出现次数

                hash2[in]++;

//判断当前字符串出现次数是否合法,如果合法,则记录一个合法字符串

                if(hash2[in]<=hash1[in]) count++;

//当right与left间的字符串长度长于wrods中所有字符串组成的长度后,我们就遍历完了一个可能是符合题意的异位词,将最前面的字符串弹出窗口,同时维护count。如果弹出的是合法的字符串,count--。

                if(right-left+1>len*size)

                {

                    string out = s.substr(left,len);

                    if(hash2[out]<=hash1[out]) count--;

                    hash2[out]--;

                    left+=len;

                }

//当count==len说明找到了一个符合题意的异位词

                if(count==size) ans.push_back(left);

            }

        }

        return ans;

    }

};

3. 69. x 的平方根 - 力扣(LeetCode)

//思路:二分查找+二段性。

//我们先从结果入手来分析本题:

//知道了二段性后,我们就可以直接套用非朴素二分查找的模板了

class Solution {

public:

    int mySqrt(int x)

    {

//处理边界情况

        if(x<1) return 0;

        int left = 1,right = x;

        while(left<right)

        {

//防止整形溢出

            long long mid = left+(right-left+1)/2;

//定位区间

            if(mid*mid<=x) left = mid;

            else right = mid-1;

        }

        return left;      

    }

};


http://www.kler.cn/a/288169.html

相关文章:

  • 网络考试系统的设计与实现【源码+文档+部署讲解】
  • 回溯算法汇总
  • CentOS 安装 NVIDIA 相关软件包时出现依赖问题
  • 四层神经网络,反向传播计算过程;四层神经网络中:y的函数公式是什么
  • MySQL的事务认识
  • 传输层(TCP、UDP、RDT详解)
  • 视频智能分析打手机检测算法安防监控打手机检测算法应用场景、算法源码、算法模型介绍
  • 计算机网络(一) —— 网络基础入门
  • JavaScript 在 VSCode 中的开发体验
  • 【数据结构】二叉搜索树的功能实现详解
  • 无人机之发动机篇
  • 谷歌的 GameNGen:无需游戏引擎,人工智能模拟 “毁灭战士“,开辟新天地
  • 24.9.1(康托展开)
  • 构建高可用的微服务架构:Spring Cloud Consul与负载均衡
  • 【C++学习笔记】预处理指令
  • 三级_网络技术_56_应用题
  • 如何本地搭建Whisper语音识别模型|语音识别|本地部署
  • C#中的ORM和EF框架
  • RK3568 驱动RTC 使用
  • 记录游戏高光时刻!4款电脑录屏工具分享
  • 牧野机床采集数据
  • 【Linux内存】Linux的内存管理机制