leetcode-字符串

1.反转字符串LeetCode344. 20230911

难度为0,此处就不放代码了

  1. 注意reverse和swap等一系列字符串函数什么时候该用,记一记库函数
  • swap可以有两种实现,涨知识了,除了temp存值还可以通过位运算:s[i] ^= s[j]; s[j] ^= s[i]; s[i] ^= s[j];
  • 2.反转字符串LeetCode541. 20230917

    这一题做的时候其实有点奇怪,想了好多方法都被自己否掉,然后看题解发现for里面i+=2k才恍然大悟,又看到reverse里面用了s.begin()+i这个用法,这才明白为啥本题本来很简洁被我写得那么复杂

    这个题在今天再重拾的时候觉得完全不用自己想,就按部就班地按着题意写就行了

    然后看到还有一个reverse的用法是reverse(s,i,i+k),第一个而是字符串,第二个和第三个是一个左闭右开的区间

    在这里插入图片描述

    3.替换空格 剑指Offer 05. 20230917

    自己做的:开了一个string,if else地一个个字符加进去了。

    卡尔说的:可以先用resize函数将s先变长到最终的长度,然后用双指针法一个一个从后往前填字符。但是在写的时候犯了一个很蠢的错误,resize之后的长度已经变了,我还在用s.length()表示旧的,s.length()+ 2 *num 表示新的。下面是正确的代码。

    class Solution {
    public:
        string replaceSpace(string s) {
            int spacenum = 0;
            for(char i : s){
                if(i == ' ') 
                    spacenum++;
            }
            int size = s.length();
            int left = size - 1;
            
            s.resize(s.length() + 2*spacenum);      
            
            for(int right = size + 2*spacenum - 1; right > 0; right--){
                if(s[left] != ' '){
                    s[right] = s[left];
                    left--;
                }
                else{
                    s[right] = '0';
                    s[right - 1] = '2';
                    s[right - 2] = '%';
                    left--;
                    right -= 2;
                }
            }
            return s;
        }
    };

    4.翻转字符串里的单词 LeetCode 151. 20230919-10/03

    思路还是蛮简单,就是写的时候老转不过弯。

    1. split函数似乎可以实现分割string里面的单词,不过C++里好像没有

    2. 学习了一下erase函数(没用到):C++标准库中的erase函数通常用于从容器(例如std::vectorstd::stringstd::list等)中删除元素,例如

    std::vector<int> myVector = {1, 2, 3, 4, 5}; // 删除第三个元素(索引为2) myVector.erase(myVector.begin() + 2);
    std::string myString = "Hello, World!"; // 删除从索引6开始的5个字符 
    
    myString.erase(6, 5);
    std::vector<int> myVector = {1, 2, 3, 4, 5, 6}; // 删除第二个到第四个元素 
    
    myVector.erase(myVector.begin() + 1, myVector.begin() + 4);

    然而,erase背后的实现是O(N)的时间复杂度,如果外面再套一个for循环就是O(N²)的复杂度。

    3. 本题写的代码,显示自己定义一个闭区间倒置函数,然后经过两次倒转就可以。里面细节非常多,什么时候+1,什么时候到末尾要判断,什么时候-1,都很凌乱

    class Solution {
    public:
        void m_reverse(string &s, int a, int b){
            for(int i = 0; i < (b - a + 1)/2; ++i){
                swap(s[a + i], s[b - i]); 
            }
        }
    
        string reverseWords(string s) {
            //去除空格
            int fast = 0, slow = 0;
            while(fast < s.length()){
                if(s[fast] != ' ')
                    s[slow++] = s[fast++];
                else if(slow != 0)
                {
                    while(s[fast] ==' ' && fast < s.length()){
                        fast++;
                    }
                    if(fast != s.length())
                        s[slow++] =' ';
                }
                else{
                    fast++;
                }
            }
            s.resize(slow);
    
            //全倒
            reverse(s.begin(),s.end());
    
            //闭区间m_reverse
            for(int i = 0, j = 0; i < s.length(); ++i){
                while(s[i] != ' ' && i < s.length())
                    ++i;
                m_reverse(s, j, i - 1);
                cout<<i<<" "<<j<<endl;
                cout<<s<<endl;
                j = i + 1;
            }
    
            return s;
        }
    };

    5.左旋转字符串 剑指Offer 58 - II 20230917

    简单的做法就是使用substr函数,注意substr的第二个参数是“多长”而不是“到哪”。

    string substr1 = s.substr(0, n);
    s = s.substr(n, s.length() - n)+ substr1;
    return s;

    然后还有原地旋转的思路:

    先局部反转,再整体反转,很妙

            reverse(s.begin(), s.begin() + n);
            reverse(s.begin() + n, s.end());
            reverse(s.begin(), s.end());

    里面两个注意点:

    一个是reverse()里面的两个参数:

    • 首先,std::vector<int> vec = {1, 2, 3, 4, 5}; auto it = vec.begin() + 2; // it指向第三个元素,即3 std::cout << *it << std::endl; // 输出 3 因为vec.begin()指向第一个元素,也即vec.begin()+0,那么+2就是指向第三个元素
  • 其次,如果是reverse(vec.begin(), vec.begin() + 2);要记住reverse的第一个参数是第一个元素,第二个参数是最后一个元素的下一个元素。也即,虽然begin()指的是1,begin()+2指的是3,但是反转的是1,2此处反转成为{2,1,3,4,5}
  • 另一个是reverse、substr的内部实现,及它们的时间复杂度

    为什么要看内部实现,因为做题的时候会想着要把时间复杂度降低,但是使用库函数有的时候就会忽略掉本身这个函数自己实现的时候用的时间复杂度,所以在这里简单看一下

    reverse: 源码实现是while ((first!=last)&&(first!=--last)) { std::iter_swap (first,last); ++first; },也就是只遍历一遍即可,而swap是之前讲过的,要么是疑惑,要么是temp存,总之是用temp和数组定位。最终合起来的结果也就是遍历一遍,对每个元素O(1)的时间复杂度,最后是O(N)。

    substr: 实现思路为创建一个新的字符串对象,将原始字符串中的子字符串复制到新的字符串中。复制的时间复杂度与子字符串的长度成正比,因此是 O(N)。

    6.找出字符串中第一个匹配项的下标-KMP LeetCode28. 20231019

    KMP居然是简单题吗,好吧

    将近一个月没写。

    这道题连着看了得有好几天了,但是依然不太会。今天终于约摸着把next数组和利用next数组进行匹配的代码写出来了,但是其实还是没有完全理解。

    
     
     
    class Solution {
    public:
        int strStr( string haystack, string needle) {
        //next数组
        int length = needle. length();
        int next[length];
        next[ 0] = 0; //
        int j = 0; // 前缀末尾
        // 求next数组
        for( int i = 1; i < length; ++i){
            while(j > 0 && needle[i] != needle[j]){
                j = next[j- 1];
            }
            if( needle[i]== needle[j]){
                j++;
            }
            next[i] = j;
        }
        int n = 0;
        //用next数组去做匹配
        for( int m = 0; m < haystack. length(); ++m){  
            while(n > 0 && haystack[m] != needle[n])
                n = next[n- 1];      
            if( haystack[m] == needle[n])
                n++;
            if(n == length)
                return m - length + 1;
        }
        return - 1;
        }
    };

    aabaa前缀(不带末尾):针对a为空;针对aa为a;针对aab为a,aa;针对aaba为a,aa,aab;针对aabaa为a,aa,aab,aaba

    后缀(不带头):针对a为空;针对aa为a;针对aab为b,ab;针对aaba为a,ba,aba;针对aabaa为a,aa,baa,abaa


    首先是求next数组。

    1)初始化的时候,next数组第一个必为0,这是因为位置0前后缀不可能相等(后缀位置0没有)。

    2)然后开始从i=1挨个填next数组,在填这个数组的时候就已经用到了kmp思想了。具体表现为填next[i]的时候,j也不是一直从头开始匹配的。j先为0,如果needle串s的s[i]!=s[j],此时说明j要往前移动,但是只移到next[j-1]那边(注意点:while、>0);如果needle串的s[i]==s[j],就j++;然后,next[i]=j,进行到next[i+1]。

    然后是利用next数组进行匹配。

    这个地方也就是遍历haystack串,与模式串匹配就两个指针都自动后移,不匹配就模式串的指针往前移(依旧是while、>0注意),然后这个地方还有一个根据题意返回一下结果。

    这个题让我自己想是完全不可能想出来的,感觉以后还得复习三遍才能记住

    7. 重复的子字符串 LeetCode 459. 20231019

    第一种解法的思想是两个s拼接起来如果去头去尾还含有s,那么s是可以由重复子串构成的。

    理解:

    [xx {xxxx][xx} xxxx] 如果{xxxxxx}=[xxxxxx],证明[xx={xx;{xx=xx];xx]=[xx};而[xx}=[xx,所以

    [xx={xx=xx]=[xx},所以xx为[xxxxxx]可用来重复的子串。大概这么理解吧,不再看严格数学证明。

    里面有两个亮点:erase函数删除特定位置的元素,以及string::npos代表没找到任何位置。

    class Solution {
    public:
        bool repeatedSubstringPattern(string s) {
            //方法1.移动匹配--具体表现为拼接-删除首尾-调用find库函数
            string ss = s+s;
            ss.erase(ss.length()-1,1);
            ss.erase(0,1);
            auto it = ss.find(s);
            if (it != string::npos)
                return 1;
            return 0;
        }
    };

    第二种解法是KMP,

    class Solution {
    public:
        bool repeatedSubstringPattern(string s) {
            //方法2.KMP--两个思路中的关键数学证明
            //1. 如果是由子串重复构成,那么最长相等前后缀不包含的那个子串就是所要求的子串。
            //2. 如果子串整除整个串,那么整个串就是由这个子串重复构成的。这个依然看我关于[xx {xxxx][xx} xxxx] 的理解,总而言之各个部分都相等。
    
            //下面,首先是算next数组,我们需要知道next[s.length()-1]等于多少,因为这个值就代表我们整个串的相等前后缀有多长。然后,用s.length()-next[s.length()-1] 除 s.length(), 如果能整除,就返回1,否则返回0。
            int length = s.size();
            //int next[length]={0};
            int next[s.length()];
            next[0] = 0;
            int j = 0;
            for (int i = 1; i < length; ++i){
                while(j > 0 && s[j]!=s[i])
                    j = next[j-1];
                if(s[j]== s[i])
                    j++;
                next[i] = j;
            }
            if(next[length-1] != 0 && (length % (length - next[length-1]) == 0))
                return 1;
            return 0;
        }
    };

    注1: next[length-1] != 0 要加,漏了完全没有相等前后缀的情形。

    注2:int next[s.length()];这种用法很奇怪,按本科讲的课来说应该写成int *next = new int[s.length()];才行。

    leetcode的奇怪机制:
    ·参数是(string s),在函数体内定义一个数组int array[s.length()];可以过
    ·int array[s.length()]={0};过不了
    ·int array[s.length()]; for (int i = 0; i < s.length(); ++i) {array[i] = 0;}又能过

    其他:LeetCode刷题总结-字符串篇 - 舞动的心 - 博客园 (cnblogs.com) (还有什么题可刷)待看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/112455.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity Animator cpu性能测试

测试案例&#xff1a; 场景中共有4000个物体&#xff0c;挂在40个animtor 上&#xff0c;每个Animator控制100个物体的动画。 使用工具&#xff1a; Unity Profiler. Unity 版本&#xff1a; unity 2019.4.40f1 测试环境&#xff1a; 手机 测试过程&#xff1a; 没有挂…

Java 设计模式——命令模式

目录 1.概述2.结构3.案例实现3.1.命令接口3.2.具体命令3.3.接受者3.4.调用者3.5.测试 4.优缺点5.使用场景6.JDK 源码解析——Runnable 1.概述 &#xff08;1&#xff09;日常生活中&#xff0c;我们出去吃饭都会遇到下面的场景&#xff1a; &#xff08;2&#xff09;命令模…

医学AI智能导诊系统源码

医院智能导诊系统是一款基于人工智能和大数据技术开发的医疗辅助软件&#xff0c;旨在为患者提供更加便捷、精准的医疗服务。 一、什么是智能导诊系统&#xff1f; 智能导诊系统是一种基于人工智能和大数据技术开发的医疗辅助软件&#xff0c;它能够通过对患者的症状、病史等信…

干货分享,大厂内部压测方案设计!

01、为什么要做压测 1、什么是压力测试&#xff1f; 不断向被测对象施加压力&#xff0c;测试系统在压力情况下的表现。 2、压力测试的目的是什么&#xff1f; 测试得出系统的极限性能指标&#xff0c;从而给出合理的承诺值或者容量告警&#xff1b; 找出系统的性能瓶颈&a…

【数据结构】树形结构所有路径复原为链表

目录 1. 树形结构可视化 2. 树形结构转为链表 此目标是要还原树形结构的所有路径。树形结构是一种常见的数据结构&#xff0c;它表示元素之间层次关系。在树形结构中&#xff0c;每个节点可能拥有一个或多个子节点&#xff0c;形成了一个分层的结构。为了还原树形结构的路径&…

区块链-蚂蚁链(阿里系产品),至信链(腾讯系),长安链(国家队)

目录 区块链-蚂蚁链&#xff08;阿里系产品&#xff09;,至信链&#xff08;腾讯系&#xff09;,长安链&#xff08;国家队&#xff09; ①蚂蚁链&#xff08;阿里系产品&#xff09; ②至信链&#xff08;腾讯系&#xff09; ③长安链&#xff08;国家队&#xff09; Hyp…

【Spring Boot 源码学习】RedisAutoConfiguration 详解

Spring Boot 源码学习系列 RedisAutoConfiguration 详解 引言往期内容主要内容1. Spring Data Redis2. RedisAutoConfiguration2.1 加载自动配置组件2.2 过滤自动配置组件2.2.1 涉及注解2.2.2 redisTemplate 方法2.2.3 stringRedisTemplate 方法 总结 引言 上篇博文&#xff0…

第一章 02Java入门-常环境变量的意义

前言 上次我们学习了常见的CMD命令,这次我们做一个用它做一个练习打开QQ(CMD方式打开),最后引出环境变量的意义。 一、CMD打开qq 可以看到,如果直接在CMD里面打开QQ,是不可以的,因为QQ的路径不在默认路径C盘,而在D盘下面的develop文件夹下面的qq下面的qq.exe下(自己…

有色金属冶炼VR虚拟场景互动教学有何优势

真实模拟&#xff1a;VR虚拟现实技术可以提供一个真实的虚拟环境&#xff0c;模拟钢铁制造现场&#xff0c;包括设备、工艺流程、操作规程等&#xff0c;使学员获得直观、真实的体验。 安全可靠&#xff1a;钢铁制造技能培训可以在虚拟环境中进行&#xff0c;不会对人员或设备造…

爆肝将近 10 万字讲解 Node.Js 详细教程

1. Node.Js 环境概述 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;用于在服务器端运行 JavaScript。它使用了一个事件驱动、非阻塞式I/O的模型&#xff0c;使得其轻量且高效。Node.js 的包管理器 npm 是全球最大的开源库生态系统。Node.js 能够响应大…

Windows安装tensorflow-gpu=1.14.0CUDA=10.0cuDNN=7.4 (多版本CUDA共存)

文章目录 0. 前置说明1. 查看版本对应关系2. 安装 cuda3. 安装 cudnn4. 添加环境变量5. 安装 tensorflow 0. 前置说明 本机&#xff08;Windows 11&#xff09;已安装CUDA 11.7 使用命令查看显卡驱动&#xff1a; nvidia-smi这里显示的CUDA Version: 11.7说明支持安装11.7版本…

python hashlib模块及实例

hashlib 模块密码加密密码撞库密码加盐 一&#xff0c;hashlib模块 hashlib模块是用来为字符串进行加密的模块&#xff0c;通过该作用就可以为用户的密码进行加密。 通过模块中的hash算法可以为任意长度的字符串加密成长度相同的一串hash值。该hash算法得到的hash值有一下几个…

汽车配件商城小程序制作 | 汽车配件售卖,高门槛但高利润

通过汽车配件商城小程序给别人的供货&#xff0c;利润可高达60%&#xff0c;但甚少有人关注汽车配件销售的行业。具体情况是怎么样的呢&#xff0c;下面给大家简单分析。 据数据显示&#xff0c;国内有4亿多辆汽车&#xff0c;这些汽车坏了要修&#xff0c;也要偶尔进行保养&am…

python实现MC协议(SLMP 3E帧)的TCP服务端(篇一)

python实现MC协议&#xff08;SLMP 3E帧&#xff09;的TCP服务端是一件稍微麻烦点的事情。它不像modbusTCP那样&#xff0c;可以使用现成的pymodbus模块去实现。但是&#xff0c;我们可以根据协议帧进行组包&#xff0c;自己去实现帧的格式&#xff0c;而这一切可以基于socket模…

清华大模型GLM

2022年,清华大学发布了一款具有重要意义的 GLM 大模型,它不仅在中文语言处理方面取得了显著的进展,还在英文语言处理方面表现出了强大的能力。GLM大模型区别于OpenAI GPT在线大模型只能通过API方式获取在线支持的窘境,GLM大模型属于开源大模型,可以本地部署进行行业微调、…

金Gien乐道 | 10月热点回顾

收获之秋&#xff0c;中电金信Q4开篇捷报不断 Q4开篇&#xff0c;中电金信迎来多个捷报。公司与青岛财通集团联合打造的核心业务系统&#xff08;一体化业务平台&#xff09;一期项目顺利投产上线并平稳运行&#xff1b;中标华南某全国性股份制商业银行新一代云原生分布式核心系…

B-5:网络安全事件响应

B-5:网络安全事件响应 任务环境说明: 服务器场景:Server2216(开放链接) 用户名:root密码:123456 1.黑客通过网络攻入本地服务器,通过特殊手段在系统中建立了多个异常进程,找出启动异常进程的脚本,并将其绝对路径作为Flag值提交; 通过nmap扫描我们发现开启了22端口,…

mfc140u.dll丢失怎么修复,mfc140u.dll文件有什么作用

今天我想和大家分享的是关于mfc140u.dll文件丢失的解决方法。在我们使用电脑的过程中&#xff0c;有时候会遇到一些错误提示&#xff0c;其中比较常见的就是“无法找到mfc140u.dll文件”。那么&#xff0c;这个文件是什么呢&#xff1f;它有什么作用呢&#xff1f; 首先&#…

springboot读取application.properties中文乱码问题

目录 1 前言&#xff1a; 2 本地环境中的解决方案&#xff08;以idea为例&#xff09; 3 全部解决方案 1 前言&#xff1a; 初用properties,读取java properties文件的时候如果value是中文&#xff0c;会出现乱码的问题。我们首先需要明了乱码问题的根源。在 Java 中&#x…

HNU-计算机网络-实验1-应用协议与数据包分析实验(Wireshark)

计算机网络 课程基础实验一 应用协议与数据包分析实验(Wireshark) 计科210X 甘晴void 202108010XXX 一、实验目的&#xff1a; 通过本实验&#xff0c;熟练掌握Wireshark的操作和使用&#xff0c;学习对HTTP协议进行分析。 二、实验内容 2.1 HTTP 协议简介 HTTP 是超文本…