leetcode-字符串

news2024/9/24 5:25:20

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) (还有什么题可刷)待看

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用electron创建桌面应用及常见打包错误解决

一、基本要求 在使用Electron进行开发之前&#xff0c;您需要安装 Node.js。 要检查 Node.js 是否正确安装&#xff0c;请在您的终端输入以下命令&#xff1a; node -v npm -v这两个命令应输出了 Node.js 和 npm 的版本信息。 二、创建应用 1、首先创建一个文件夹 mkdir …

C++项目——云备份-⑨-服务端与客户端功能联调

文章目录 专栏导读1.服务端源代码2.客户端源代码3.浏览器访问测试//listshow 4.上传文件测试5.文件下载测试 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计划导师&#xff0c;阿里云专家博主&…

基于黄金正弦算法的无人机航迹规划-附代码

基于黄金正弦算法的无人机航迹规划 文章目录 基于黄金正弦算法的无人机航迹规划1.黄金正弦搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用黄金正弦算法来优化无人机航迹规划。 …

NumPy教程(快速入门版)

NumPy 是基于Python的数学计算库&#xff0c;擅长处理数组/矩阵。 NumPy 是 Numerical Python 的缩写&#xff0c;它是一个由多维数组对象&#xff08;ndarray&#xff09;和处理这些数组的函数&#xff08;function&#xff09;集合组成的库。使用 NumPy 库&#xff0c;可以对…

修仙路上的基石->java内置的占位符

java内的占位符 System.out.println(String.format("牛逼logger记录:%s",message)); 在 Java 中&#xff0c;%s 是一个格式化字符串的占位符&#xff0c;用于表示后续参数中的字符串值。在 String.format() 方法中&#xff0c;%s 会被替换为相应的参数值。在给定的例…

Ubuntu 搭建 DHCP ivp6 server 步骤

Ubuntu 搭建 DHCP ivp6 server 步骤 安装 DHCP server安装 radvd&#xff08;实现局域网路由功能)测试运行 安装 DHCP server apt 安装 isc-dhcp-server sudo apt-get install isc-dhcp-server修改配置文件 /etc/dhcp/dhcpd6.conf 内容如下&#xff1a; lease-time 7200; lo…

chatgpt生成文本的底层工作原理是什么?

文章目录 &#x1f31f; ChatGPT生成文本的底层工作原理&#x1f34a; 一、数据预处理&#x1f34a; 二、模型结构&#x1f34a; 三、模型训练&#x1f34a; 四、文本生成&#x1f34a; 总结 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN…

四十一、【进阶】索引使用SQL提示

1、SQL提示使用情景 在使用MySQL时&#xff0c;当一个字段参在于多个索引中时&#xff0c;默认情况下&#xff0c;MySQL会自动选择一个索引&#xff0c;但我们可以指定索引吗&#xff1f;可以忽略某一种索引吗&#xff1f; 答案是可以的。 前提&#xff1a;profession字段已经…

算法通关村第四关-黄金挑战栈的经典问题

括号匹配问题 描述 : 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有…

【Linux】内存精讲

TOC 目录 程序在计算机中的运行方式 CPU的指令 虚拟内存是什么&#xff1f; CPU的数据处理能力 &#xff08;1&#xff09;16位CPU &#xff08;2&#xff09;32位CPU &#xff08;3&#xff09;64位CPU 编译模式 32位编译模式 64位编译模式 C语言内存对齐 内存分…

终于有人把腾讯云轻量服务器“月流量”说明白了

腾讯云轻量服务器月流量什么意思&#xff1f;月流量是指轻量服务器限制每月流量的意思&#xff0c;不能肆无忌惮地使用公网&#xff0c;流量超额需要另外支付流量费&#xff0c;上海/广州/北京等地域的轻量服务器月流量不够用超额部分按照0.8元/GB的价格支付流量费。阿腾云aten…

2011-2021年上市公司百度指数数据

2011-2021年上市公司百度指数数据 1、时间&#xff1a;2011-2021年 2、指标&#xff1a;股票代码、股票名称、年份、类型、PC移动、PC端、移动端 3、来源&#xff1a;百度指数 4、范围&#xff1a;上市公司 5、样本量&#xff1a;7.4W 6、指标解释&#xff1a;百度指数&a…

为什么要进行兼容性测试? 常见方法有哪些?

在当今数字化的世界中&#xff0c;用户通过各种设备和平台访问应用程序和网站。为了确保用户体验的一致性和质量&#xff0c;兼容性测试成为了软件开发周期中不可或缺的一环。本文将深入探讨什么是兼容性测试&#xff0c;为什么它是如此重要&#xff0c;以及一些常见的兼容性测…

各传输介质详细知识点

一.百兆网传输介质 快速以太网(802.3u) 100Base-T2 电缆&#xff1a;2对3类UTP 最大段长&#xff1a;100m 特性阻抗&#xff1a;100 100Base-T4 电缆&#xff1a;4对3类UTP 最大段长&#xff1a;100m 特点&#xff1a;8B/6T&#xff0c;NRZ编码 特性阻抗&#xff1a;1…

【多线程面试题十九】、 公平锁与非公平锁是怎么实现的?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a; 公平锁与非公平锁是怎么…

安装OPENCMS过程记录

今天尝试安装个人网站&#xff0c;或者说是内容管理系统&#xff0c;wordpress 是PHP的&#xff0c;所以上网找了一个免费的&#xff0c;在知乎上基于Java的开源CMS有哪些推荐&#xff0c;各自特点是什么 - 知乎 (zhihu.com) 找了这个opencms&#xff0c;据说是免费&#xff0…

腾讯云轻量应用服务器“月流量”不够用怎么办?

腾讯云轻量应用服务器“月流量”不够用怎么办&#xff1f;超额部分支付流量费&#xff0c;价格为0.8元/GB。腾讯云轻量服务器月流量什么意思&#xff1f;月流量是指轻量服务器限制每月流量的意思&#xff0c;不能肆无忌惮地使用公网&#xff0c;流量超额需要另外支付流量费&…

【设计模式】第8节:结构型模式之“适配器模式”

一、简介 适配器模式是用来做适配的&#xff0c;它将不兼容的接口转换为可兼容的接口&#xff0c;让原本由于接口不兼容而不能一起工作的类可以一起工作。 适配器模式角色&#xff1a; 请求者client&#xff1a;调用服务的角色目标Target&#xff1a;定义了Client要使用的功…

前端开发必备技能!用简单CSS代码绘制三角形,提升用户体验

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、前…