LeetCode第6~10题解

CONTENTS

    • LeetCode 6. N 字形变换(中等)
    • LeetCode 7. 整数反转(中等)
    • LeetCode 8. 字符串转换整数-atoi(中等)
    • LeetCode 9. 回文数(简单)
    • LeetCode 10. 正则表达式匹配(困难)

LeetCode 6. N 字形变换(中等)

【题目描述】

将一个给定字符串 s 根据给定的行数 numRows,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"
请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

【示例1】

输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"

【示例2】

输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I

【示例3】

输入:s = "A", numRows = 1
输出:"A"

【提示】

1 ≤ s . l e n g t h ≤ 1000 1\le s.length\le 1000 1s.length1000
1 ≤ n u m R o w s ≤ 1000 1\le numRows\le 1000 1numRows1000
s 由英文字母(小写和大写)、',''.' 组成

【分析】


在这里插入图片描述

如上图所示,我们用数字来观察规律,设行数为 n n n

首先看第一行,0到6一共间隔 2 n − 2 2n-2 2n2 个数,因为从0走到3有 n − 1 n-1 n1 个数,3走到6也有 n − 1 n-1 n1 个数,因此第一行为从0开始的公差为 2 n − 2 2n-2 2n2 的等差数列。同理最后一行为从 n − 1 n-1 n1 开始的公差为 2 n − 2 2n-2 2n2 的等差数列。

对于中间行,以第二行为例,由两个等差数列组成,一个是在直线上的数列:1、7、13,这是从1开始的公差为 2 n − 2 2n-2 2n2 的等差数列;还有一个是在斜线上的数列:5、11、17,这是从5(可以看成 2 n − 2 − i 2n-2-i 2n2i i i i 表示这一行的第一个数)开始的公差为 2 n − 2 2n-2 2n2 的等差数列。因此中间行就是先输出第一个等差数列的第一项,然后输出第二个等差数列的第一项,再输出第一个等差数列的第二项,以此类推。


【代码】

class Solution {
public:
    string convert(string s, int n) {
        if (n == 1) return s;  // 特判
        string res;
        for (int i = 0; i < n; i++)
        {
            if (i == 0 || i == n - 1)  // 第一行或最后一行
                for (int j = i; j < s.size(); j += 2 * n - 2)
                    res += s[j];
            else
                // j表示第一个等差数列,k表示第二个等差数列
                for (int j = i, k = 2 * n - 2 - i; j < s.size() || k < s.size(); j += 2 * n - 2, k += 2 * n - 2)
                {
                    if (j < s.size()) res += s[j];
                    if (k < s.size()) res += s[k];
                }
        }
        return res;
    }
};

LeetCode 7. 整数反转(中等)

【题目描述】

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [ − 2 31 , 2 31 − 1 ] [-2^{31}, 2^{31} - 1] [231,2311],就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。

【示例1】

输入:x = 123
输出:321

【示例2】

输入:x = -123
输出:-321

【示例3】

输入:x = 120
输出:21

【示例4】

输入:x = 0
输出:0

【提示】

− 2 31 ≤ x ≤ 2 31 − 1 -2^{31}\le x\le 2^{31} - 1 231x2311

【分析】


首先有个小 Tips:C++中负数取模的结果也为负数,如 − 1234 % 10 = − 4 -1234\% 10=-4 1234%10=4

直接用 x % 10 x\% 10 x%10 求出 x x x 的个位数 a a a,然后 r e s = r e s ∗ 10 + a res=res*10+a res=res10+a,根据负数取模的特性易知该方式同样适用于负数。

注意我们当做无法使用 long long 类型,因此做溢出判断的时候需要对判断公式做一个变换。


【代码】

class Solution {
public:
    int reverse(int x) {
        int res = 0;
        while (x)
        {
            // res * 10 + x % 10 > MAX -> res > (MAX - x % 10) / 10
            if (res > 0 && res > (INT_MAX - x % 10) / 10) return 0;
            if (res < 0 && res < (INT_MIN - x % 10) / 10) return 0;
            res = res * 10 + x % 10;  // x不管正负都通用
            x /= 10;
        }
        return res;
    }
};

LeetCode 8. 字符串转换整数-atoi(中等)

【题目描述】

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符串末尾)为正还是负号,读取该字符(如果有)。确定最终结果是负数还是正数。如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,“123” -> 123,“0032” -> 32)。如果没有读入数字,则整数为 0。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [ − 2 31 , 2 31 − 1 ] [-2^{31}, 2^{31} - 1] [231,2311],需要截断这个整数,使其保持在这个范围内。具体来说,小于 − 2 31 -2^{31} 231 的整数应该被固定为 − 2 31 -2^{31} 231,大于 2 31 − 1 2^{31}-1 2311 的整数应该被固定为 − 2 31 − 1 -2^{31}-1 2311
  6. 返回整数作为最终结果。

注意:

  • 本题中的空白字符只包括空格字符 ' '
  • 除前导空格或数字后的其余字符串外,请勿忽略任何其他字符。

【示例1】

输入:s = "42"
输出:42

【示例2】

输入:s = "   -42"
输出:-42

【示例3】

输入:s = "4193 with words"
输出:4193

【提示】

0 ≤ s . l e n g t h ≤ 200 0\le s.length\le 200 0s.length200
s 由英文字母(大写和小写)、数字(0-9)、' ''+''-''.' 组成

【分析】


模拟处理字符串即可,判断溢出的方式与上一题相似,唯一的一个坑点是负数的最小值的绝对值是比正数的最大值多1的,因此当恰好等于最小值时 r e s res res 存不下对应的正数,因此需要直接返回最小值。


【代码】

class Solution {
public:
    int myAtoi(string s) {
        int idx = 0;
        while (idx < s.size() && s[idx] == ' ') idx++;  // 过滤前导空格
        int op = 1;  // 标记正负,没有正负号时默认为正
        if (s[idx] == '-') op *= -1, idx++;
        else if (s[idx] == '+') idx++;
        int res = 0;
        while (idx < s.size() && s[idx] >= '0' && s[idx] <= '9')
        {
            int x = s[idx] - '0';
            // res * 10 + x > MAX -> res > (MAX - x) / 10
            if (op > 0 && res > (INT_MAX - x) / 10) return INT_MAX;
            // -res * 10 - x < MIN -> -res < (MIN + x) / 10
            if (op < 0 && -res < (INT_MIN + x) / 10) return INT_MIN;
            if (-res * 10 - x == INT_MIN) return INT_MIN;  // 特判刚好等于最小值
            res = res * 10 + x;
            idx++;
        }
        return res * op;
    }
};

LeetCode 9. 回文数(简单)

【题目描述】

给你一个整数 x,如果 x 是一个回文整数,返回 true;否则,返回 false
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。

【示例1】

输入:x = 121
输出:true

【示例2】

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

【示例3】

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

【提示】

− 2 31 ≤ x ≤ 2 31 − 1 -2^{31}\le x\le 2^{31} - 1 231x2311

【分析】


简单题,可以转换成字符串来做,也可以使用数值方法来做,用之前的方法逐步将 x x x 的个位取出来构建出新的数,然后判断两数是否相等即可。


【代码】

【字符串解法】

class Solution {
public:
    bool isPalindrome(int x) {
        if (x < 0) return false;  // 负数一定不是回文数
        string s = to_string(x);
        return s == string(s.rbegin(), s.rend());
    }
};

【数值解法】

class Solution {
public:
    bool isPalindrome(int x) {
        if (x < 0) return false;  // 负数一定不是回文数
        long long res = 0;  // 1234567899之类的数翻转后会溢出int
        int tmp = x;
        while (tmp) res = res * 10 + tmp % 10, tmp /= 10;
        return res == x;
    }
};

LeetCode 10. 正则表达式匹配(困难)

【题目描述】

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.''*' 的正则表达式匹配。

  • '.' 匹配任意单个字符
  • '*' 匹配零个或多个前面的那一个元素
  • 所谓匹配,是要涵盖整个字符串 s 的,而不是部分字符串。

【示例1】

输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

【示例2】

输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

【示例3】

输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')

【提示】

1 ≤ s . l e n g t h ≤ 20 1\le s.length\le 20 1s.length20
1 ≤ p . l e n g t h ≤ 20 1\le p.length\le 20 1p.length20
s 只包含从 a-z 的小写字母
p 只包含从 a-z 的小写字母,以及字符 .*
保证每次出现字符 * 时,前面都匹配到有效的字符

【分析】


这题很难想到是 DP 问题,因此难度不小。我们一步步分析状态表示和状态计算:

  • 状态表示 f [ i ] [ j ] f[i][j] f[i][j]
    • 集合:所有 s [ 1 ∼ i ] s[1\sim i] s[1i] p [ 1 ∼ j ] p[1\sim j] p[1j](下标从1开始)的匹配方案。
    • 属性:bool 类型,表示是否存在一个合法方案。
  • 状态计算:
    • p [ j ] ≠ ∗ p[j]\ne * p[j]=,那么直接看 s [ i ] s[i] s[i] p [ j ] p[j] p[j] 是否匹配即可,若 s[i] == p[j] 或者 p[j] == '.',且满足 s s s 的前 i − 1 i-1 i1 个字符和 j j j 的前 j − 1 j-1 j1 个字符也匹配,那么 s [ i ] s[i] s[i] p [ j ] p[j] p[j] 匹配,即可以写出以下状态转移方程:
      f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.')
    • p [ j ] = ∗ p[j]=* p[j]=,那么我们需要枚举一下 * 表示多少个字符,如果表示0个字符,则 s s s 的前 i i i 个字符和 j j j 的前 j − 2 j-2 j2 个字符匹配;如果表示1个字符,则 s s s 的前 i − 1 i-1 i1 个字符和 j j j 的前 j − 2 j-2 j2 个字符匹配,且 s[i] == p[j - 1];如果表示2个字符,则 s s s 的前 i − 2 i-2 i2 个字符和 j j j 的前 j − 2 j-2 j2 个字符匹配,且 s[i - 1] == p[j - 1] && s[i] == p[j - 1]。因此可以写出以下状态转移方程(没有将 p[j - 1] == '.' 写进去,别忘了这种情况也算匹配):
      f[i][j] = f[i][j - 2] || (f[i - 1][j - 2] && s[i] == p[j - 1]) || (f[i - 2][j - 2] && s[i - 1] == p[j - 1] && s[i] == p[j - 1]) ...
      现在我们进行优化,写出 f[i - 1][j] 的状态转移方程如下:
      f[i - 1][j] = f[i - 1][j - 2] || (f[i - 2][j - 2] && s[i - 1] == p[j - 1]) ...
      因此可以写出优化后的状态转移方程(将 p[j - 1] == '.' 考虑进去):
      f[i][j] = f[i][j - 2] || f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '*')

【代码】

class Solution {
public:
    bool isMatch(string s, string p) {
        int n = s.size(), m = p.size();
        s = ' ' + s, p = ' ' + p;  // 在首部加一个空格,因为我们要从第一位开始
        vector<vector<bool>> f(n + 1, vector<bool>(m + 1));
        f[0][0] = true;
        for (int i = 0; i <= n; i++)
            for (int j = 1; j <= m; j++)  // p为空肯定无法匹配,而s为空不一定
            {
                if (i && p[j] != '*')  // 注意i不能为0,因为需要使用f[i - 1]
                    f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
                else if (p[j] == '*')
                    // 同样注意i不能为0
                    f[i][j] = f[i][j - 2] || i && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.');
            }
        return f[n][m];
    }
};

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

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

相关文章

Flutter 混合开发调试

针对Flutter开发的同学来说&#xff0c;大部分的应用还是Native Flutter的混合开发&#xff0c;所以每次改完Flutter代码&#xff0c;运行整个项目无疑是很费时间的。所以Flutter官方也给我们提供了混合调试的方案【在混合开发模式下进行调试】&#xff0c;这里以Android Stud…

VUE笔记(四)vue的组件

一、组件的介绍 1、组件的作用 整个项目都是由组件组成 可以让代码复用&#xff1a;相似结构代码可以做成一个组件&#xff0c;直接进行调用就可以使用&#xff0c;提高代码复用性 可以让代码具有可维护性&#xff08;只要改一处&#xff0c;整个引用的部分全部都变&#xf…

Java8实战-总结17

Java8实战-总结17 引入流流操作中间操作终端操作使用流 小结 引入流 流操作 java.util.stream.Stream中的Stream接口定义了许多操作。它们可以分为两大类。再来看一下前面的例子&#xff1a; List<String> names menu.stream() //从菜单获得流 .filter(d -> d.get…

SpringBoot - Google EventBus、AsyncEventBus

介绍 EventBus 顾名思义&#xff0c;事件总线&#xff0c;是一个轻量级的发布/订阅模式的应用模式&#xff0c;最初设计及应用源与 google guava 库。 相比于各种 MQ 中间件更加简洁、轻量&#xff0c;它可以在单体非分布式的小型应用模块内部使用&#xff08;即同一个JVM范围…

xml和json互转工具类

分享一个json与xml互转的工具类&#xff0c;非常好用 一、maven依赖 <!-->json 和 xm 互转</!--><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency&g…

图形化管理工具ossbrowser

文章目录 一、OSS介绍二、通过工具管理OSS三、安装四、使用-通过AK五、免责声明摘抄 一、OSS介绍 云对象存储OSS&#xff08;Object Storage Service&#xff09;是一款海量、安全、低成本、高可靠的云存储服务&#xff0c;可提供99.9999999999%&#xff08;12个9&#xff09;…

Javaweb入门

Spring Spring发展到今天已经形成一种开发生态圈&#xff0c;Spring提供若干个子项目&#xff0c;每个项目用于完成特定的功能。 Spring Boot可以帮助我们非常快速的构建应用程序、简化开发、提高效率 SpringBootWeb入门 需求&#xff1a;使用Spring Boot开发一个web应用&a…

结构体(个人学习笔记黑马学习)

1、结构体的定义和使用 #include <iostream> using namespace std; #include <string>struct Student {string name;int age;int score; }s3;int main() {//1、struct Student s1;s1.name "张三";s1.age 18;s1.score 100;cout << "姓名&a…

便携式水质自动采样器可应用的场景

便携式水质自动采样器符合中国环境保护部HJ/T 372-2007《水质自动采样器技术要求及检测方法》&#xff0c;是集流量测量、水样采集&#xff0c;自动分瓶、一体的多功能环境监测仪器。 具有体积小&#xff0c;方便移动、操作简捷、环保节能等特点。适用于各级环境监测站、监察机…

go vet中的那些检测项

go vet 是 Go 语言自带的一个工具&#xff0c;用于分析 Go 代码中的常见错误和潜在问题。它可以检查代码中可能存在的各种问题&#xff0c;例如&#xff1a; 未使用的变量、函数或包 可疑的函数调用 错误的函数签名 程序中的竞态条件 错误的类型转换等 本文意图指令当前go vet所…

【VUE】数字动态变化到目标值-vue-count-to

vue-count-to是一个Vue组件&#xff0c;用于实现数字动画效果。它可以用于显示从一个数字到另一个数字的过渡动画。 插件名&#xff1a;vue-count-to 官方仓库地址&#xff1a;GitHub - PanJiaChen/vue-countTo: Its a vue component that will count to a target number at a…

VueX 与Pinia 一篇搞懂

VueX 简介 Vue官方&#xff1a;状态管理工具 状态管理是什么 需要在多个组件中共享的状态、且是响应式的、一个变&#xff0c;全都改变。 例如一些全局要用的的状态信息&#xff1a;用户登录状态、用户名称、地理位置信息、购物车中商品、等等 这时候我们就需要这么一个工…

【二等奖方案】大规模金融图数据中异常风险行为模式挖掘赛题「Aries」解题思路

第十届CCF大数据与计算智能大赛&#xff08;2022 CCF BDCI&#xff09;已圆满结束&#xff0c;大赛官方竞赛平台DataFountain&#xff08;简称DF平台&#xff09;正在陆续释出各赛题获奖队伍的方案思路&#xff0c;欢迎广大数据科学家交流讨论。 本方案为【大规模金融图数据中…

查局域网所有占用IP

查局域网所有占用IP 按&#xff1a;winr 出现下面界面&#xff0c;在文本框中输入 cmd 按确定即可出现cmd命令界面 在cmd命令窗口输入你想要ping的网段&#xff0c;下面192.168.20.%i即为你想要ping的网段&#xff0c;%i代表0-255 for /L %i IN (1,1,254) DO ping -w 1 -n 1…

尚硅谷SpringMVC

五、域对象共享数据 1、使用ServletAPI向request域对象共享数据 首页&#xff1a; Controller public class TestController {RequestMapping("/")public String index(){return "index";} } <!DOCTYPE html> <html lang"en" xmln…

十五、模板方法模式

一、什么是模板方法模式 模板方法&#xff08;Template Method&#xff09;模式的定义如下&#xff1a;定义一个操作中的算法骨架&#xff0c;而将算法的一些步骤延迟到子类中&#xff0c;使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 模板方法模式包含以…

Sharding-JDBC(九)5.3.0版本,实现按月分表、自动建表、自动刷新节点

目录 一、简介二、Maven依赖三、配置文件application.ymlsharding.yaml 四、代码实现1.自动建表、自动刷新节点思路2.创建表结构3.TimeShardingAlgorithm.java 分片算法类4.ShardingAlgorithmTool.java 分片工具类5.ShardingTablesLoadRunner.java 初始化缓存类6.SpringUtil.ja…

postgresql-子查询

postgresql-子查询 简介派生表IN 操作符ALL 操作符ANY 操作符关联子查询横向子查询EXISTS 操作符 简介 子查询&#xff08;Subquery&#xff09;是指嵌套在其他 SELECT、INSERT、UPDATE 以及 DELETE 语句中的 查询语句。 子查询的作用与多表连接查询有点类似&#xff0c;也是为…

学习JAVA打卡第四十五天

StringBuffer类 StringBuffer对象 String对象的字符序列是不可修改的&#xff0c;也就是说&#xff0c;String对象的字符序列的字符不能被修改、删除&#xff0c;即String对象的实体是不可以再发生变化&#xff0c;例如&#xff1a;对于 StringBuffer有三个构造方法&#xff…