怒刷LeetCode的第4天(Java版)

news2025/1/12 16:13:27

#【中秋征文】程序人生,中秋共享#

目录

第一题

题目来源

题目内容

解决方法

方法一:遍历字符串

方法二:有限状态机(Finite State Machine)

方法三:正则表达式

第二题

题目来源

题目内容

解决方法

方法一:反转数字比较

第三题

题目来源

题目内容

解决方法

方法一:动态规划

方法二:递归回溯


第一题

题目来源

8. 字符串转换整数 (atoi) - 力扣(LeetCode)

题目内容

解决方法

方法一:遍历字符串

题目要求实现一个字符串转换整数的函数,即将给定字符串转换成一个32位有符号整数。

解题思路如下:

  1. 去除字符串开头的空格。

  2. 判断接下来的字符是否为正号或者负号,如果是则记录符号并向后移动一位。

  3. 遍历剩余的字符串字符,直到遇到非数字字符为止。将遇到的数字字符转换成整数,并累加到结果中。

  4. 根据符号和结果判断最终返回的整数值。

  5. 注意处理越界情况,如果超出32位有符号整数的取值范围,则返回边界值。

class Solution {
    public int myAtoi(String s) {
    // 去除前导空格
    s = s.trim();
    
    // 处理空字符串和只有正负号的情况
    if (s.length() == 0 || (s.length() == 1 && (s.charAt(0) == '+' || s.charAt(0) == '-'))) {
        return 0;
    }
    
    // 判断第一个非空字符是否为正负号
    boolean positive = true;
    int i = 0;
    if (s.charAt(0) == '+' || s.charAt(0) == '-') {
        if (s.charAt(0) == '-') {
            positive = false;
        }
        i++;
    }
    
    // 提取连续的数字字符并转换为整数
    long result = 0; // 使用长整型,防止溢出
    while (i < s.length() && Character.isDigit(s.charAt(i))) {
        int digit = s.charAt(i) - '0';
        result = result * 10 + digit;
        
        // 判断是否超出范围
        if (positive && result > Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        } else if (!positive && result * -1 < Integer.MIN_VALUE) {
            return Integer.MIN_VALUE;
        }
        
        i++;
    }
    
    // 根据正负号返回最终结果
    return positive ? (int)result : (int)(result * -1);
}
}

这个函数首先去除字符串的前导空格,然后判断字符串是否为空或只有正负号的情况,如果是,则返回0。接下来,判断第一个非空字符是正号还是负号,并将其处理为正负标志。然后,遍历字符串的剩余部分,将连续的数字字符转换为整数,并判断是否超出范围。最后,根据正负标志返回最终结果。 

下面是该解决方案的复杂度分析:

  • 时间复杂度:O(n),其中 n 是字符串的长度。在算法中,我们只遍历字符串一次。
  • 空间复杂度:O(1)。除了存储结果之外,算法使用的额外空间是固定大小的变量,并不随输入的规模而改变。

需要注意的是,在判断是否超出范围时,我们使用了长整型变量 result,而不是直接使用整型变量。这是因为如果 result 溢出 32 位有符号整数的范围,将无法正确判断溢出。所以我们将连续数字字符转换为长整型,然后再判断是否超出范围,并根据正负号返回最终结果。

LeetCode运行结果:

方法二:有限状态机(Finite State Machine)

还有其他方法可以解决这个问题。一种常见的方法是使用有限状态机(Finite State Machine)。有限状态机的基本思想是根据输入的字符和当前状态进行状态转移,最终得到结果。

class Solution {
    public int myAtoi(String s) {
    Automaton automaton = new Automaton();
    for (char c : s.toCharArray()) {
        if (!automaton.process(c)) {
            break;
        }
    }
    return (int) (automaton.sign * automaton.result);
}

class Automaton {
    public int sign = 1; // 符号,默认为正号
    public long result = 0; // 结果,默认为0
    private String state = "start"; // 初始状态
    
    private Map<String, String[]> transitionTable = new HashMap<>(){{
        put("start", new String[]{"start", "signed", "inNumber", "end"});
        put("signed", new String[]{"end", "end", "inNumber", "end"});
        put("inNumber", new String[]{"end", "end", "inNumber", "end"});
        put("end", new String[]{"end", "end", "end", "end"});
    }};
    
    public boolean process(char c) {
        state = transitionTable.get(state)[getStateIndex(c)];
        if ("inNumber".equals(state)) {
            result = result * 10 + (c - '0');
            result = sign == 1 ? Math.min(result, Integer.MAX_VALUE) : Math.min(result, -1L * Integer.MIN_VALUE);
        } else if ("signed".equals(state)) {
            sign = c == '+' ? 1 : -1;
        } else if ("end".equals(state)) {
            return false;
        }
        return true;
    }
    
    private int getStateIndex(char c) {
        if (c == ' ') {
            return 0;
        }
        if (c == '+' || c == '-') {
            return 1;
        }
        if (Character.isDigit(c)) {
            return 2;
        }
        return 3;
    }
}
}

在这个解决方案中,我们使用了一个包含四个状态的有限状态机。根据当前状态和输入字符的类型,我们进行状态转移,并更新符号和结果。具体的状态转移规则可以在 transitionTable 中定义。

这个解决方案的时间复杂度为 O(n),空间复杂度为 O(1)。

LeetCode运行结果:

方法三:正则表达式

正则表达式是一种强大的模式匹配工具,可以用来匹配和提取字符串中的特定模式。

import java.util.regex.Pattern;
import java.util.regex.Matcher;

class Solution {
    public int myAtoi(String s) {
    String pattern = "^\\s*([+-]?\\d+)";
    Pattern regex = Pattern.compile(pattern);
    Matcher matcher = regex.matcher(s);
    
    if(matcher.find()) {
        try {
            long num = Long.parseLong(matcher.group(1));
            
            if (num > Integer.MAX_VALUE) {
                return Integer.MAX_VALUE;
            } else if (num < Integer.MIN_VALUE) {
                return Integer.MIN_VALUE;
            } else {
                return (int) num;
            }
        } catch (NumberFormatException e) {
            // 处理超出整数范围的情况
            if (matcher.group(1).charAt(0) == '-') {
                return Integer.MIN_VALUE;
            } else {
                return Integer.MAX_VALUE;
            }
        }
    }
    
    return 0; // 如果无法匹配数字,则返回0
}
}

在这个解决方案中,我们使用了正则表达式 ^\\s*([+-]?\\d+) 来匹配字符串中的数字。首先,使用 Pattern 类编译正则表达式,并使用 Matcher 类对输入字符串进行匹配。如果在字符串中找到一个或多个数字序列,我们尝试将其转换为长整型 num。然后,我们检查 num 是否超出了整数的范围,并根据结果返回相应的值。

这个解决方案的时间复杂度取决于正则表达式的匹配速度,通常为 O(n)。空间复杂度为 O(1),因为只使用了有限的变量来存储结果。

LeetCode运行结果:

第二题

题目来源

9. 回文数 - 力扣(LeetCode)

题目内容

解决方法

方法一:反转数字比较

class Solution {
    public boolean isPalindrome(int x) {
    // 处理特殊情况,负数和以0结尾的非零数不可能是回文数
    if (x < 0 || (x % 10 == 0 && x != 0)) {
        return false;
    }
    
    int reverse = 0;
    int original = x;
    while (x > 0) {
        int digit = x % 10;
        reverse = reverse * 10 + digit;
        x /= 10;
    }
    
    return original == reverse;
}

}

在这个解决方案中,我们首先处理了一些特殊情况:负数和以0结尾的非零数不可能是回文数。然后,我们使用一个循环,将输入的数字逐位反转并保存到变量 reverse 中。最后,我们检查反转后的数字是否等于原始数字 x。

这个方法的时间复杂度是 O(log n),其中 n 是 x 的位数。空间复杂度是 O(1)。

LeetCode运行结果:

第三题

题目来源

10. 正则表达式匹配 - 力扣(LeetCode)

题目内容

解决方法

方法一:动态规划

这是一个经典的正则表达式匹配问题,可以使用动态规划来解决。具体的思路如下:

  1. 定义一个二维布尔数组 dp,其中 dp[i][j] 表示 s 的前 i 个字符是否与 p 的前 j 个字符匹配。
  2. 初始化 dp[0][0] 为 true,表示空字符可以匹配。
  3. 对于第一行 dp[0][j]:如果 p[j-1] 是 '',则可以把 p[j-2] 和 '' 一起消去,即 dp[0][j] = dp[0][j-2];否则为 false。
  4. 对于其他行 dp[i][j]:
    • 如果 p[j-1] 是字母或者 '.',则判断当前字符能否匹配,即 dp[i][j] = dp[i-1][j-1];
    • 如果 p[j-1] 是 '*',有两种情况:
      • "表示匹配零次前面的元素,即将 p[j-2] 和 "一起消去,即 dp[i][j] = dp[i][j-2];
      • '*' 表示匹配一次或多次前面的元素,即当前字符与 p[j-2] 匹配且前一个字符匹配(dp[i-1][j])。

最后,返回 dp[s.length()][p.length()]。

class Solution {
public boolean isMatch(String s, String p) {
    int m = s.length();
    int n = p.length();
    
    // 创建并初始化 dp 数组
    boolean[][] dp = new boolean[m + 1][n + 1];
    dp[0][0] = true; // 空字符串和空模式匹配
    
    // 处理边界情况,s 为空字符串时的匹配
    for (int j = 1; j <= n; j++) {
        if (p.charAt(j - 1) == '*') {
            dp[0][j] = dp[0][j - 2]; // '*' 可以将前面的字符匹配 0 次
        }
    }
    
    // 动态规划求解
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            // 如果当前字符匹配,则和上一个字符的匹配结果一致
            if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') {
                dp[i][j] = dp[i - 1][j - 1];
            } else if (p.charAt(j - 1) == '*') {
                // 如果遇到 '*' 字符,有两种情况:
                // 1. '*' 匹配了前一个字符 0 次,则和 p 的前两个字符匹配结果一致
                // 2. '*' 匹配了前一个字符多次,则当前字符和前面的模式字符串匹配,
                //    并且和上一个字符的匹配结果一致
                dp[i][j] = dp[i][j - 2]; // 匹配 0 次的情况
                if (p.charAt(j - 2) == '.' || p.charAt(j - 2) == s.charAt(i - 1)) {
                    dp[i][j] = dp[i][j] || dp[i - 1][j];
                }
            }
        }
    }
    
    return dp[m][n];
}

}

这个算法的时间复杂度是 O(m * n),其中 m 是字符串 s 的长度,n 是模式 p 的长度。空间复杂度是 O(m * n)。 

LeetCode运行结果:

方法二:递归回溯

除了动态规划,还可以使用递归回溯的方法来解决。具体的思路是从左到右依次匹配字符,对于每个字符,有如下几种情况:

  1. 如果当前字符和模式字符相同,或者模式字符是 '.',则继续匹配下一个字符。
  2. 如果模式字符是 '*',有两种情况:
    • 模式字符和前一个字符不匹配,并且当前字符也和模式字符的前一个字符不匹配,则只能将 '*' 视为匹配 0 次前面的字符,继续匹配后面的字符。
    • 其他情况下,可以将 '*' 视为匹配 0 次、1 次或多次前面的字符,然后继续匹配下一个字符。

如果能够成功匹配到最后一个字符,则字符串和字符规律匹配成功。

class Solution {
public boolean isMatch(String s, String p) {
        if (p.isEmpty()) {
            return s.isEmpty();
        }

        boolean firstMatch = !s.isEmpty() && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.');
        
        if (p.length() >= 2 && p.charAt(1) == '*') {
            return isMatch(s, p.substring(2)) || (firstMatch && isMatch(s.substring(1), p));
        } else {
            return firstMatch && isMatch(s.substring(1), p.substring(1));
        }
    }
}

复杂度分析:

  • 时间复杂度:最坏情况下,对于每个字符都存在两种选择(匹配 0 次或多次),因此时间复杂度是指数级的,即 O(2^(m + n)),其中 m 和 n 分别是字符串 s 和模式 p 的长度。
  • 空间复杂度:递归过程中需要消耗额外的栈空间,最坏情况下递归深度是字符串 s 和模式 p 的长度的和,因此空间复杂度为 O(m + n)。

综上所述,动态规划方法在时间和空间复杂度上都优于递归回溯方法。在实际应用中,建议使用动态规划方法来解决这个问题,尤其是在输入规模较大时。

LeetCode运行结果:

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

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

相关文章

机器学习——决策树/随机森林

0、前言&#xff1a; 决策树可以做分类也可以做回归&#xff0c;决策树容易过拟合决策树算法的基本原理是依据信息学熵的概念设计的&#xff08;Logistic回归和贝叶斯是基于概率论&#xff09;&#xff0c;熵最早起源于物理学&#xff0c;在信息学当中表示不确定性的度量&…

带你了解前后端分离的秘密-Vue【vue入门】

&#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Vue》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一定基础的程序员&#xff0c;这个专栏…

js中事件委托和事件绑定之间的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 事件绑定&#xff08;Event Binding&#xff09;⭐事件委托&#xff08;Event Delegation&#xff09;⭐ 选择事件绑定或事件委托⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本…

NVM安装及如何使用NVM

NVM是什么&#xff1f; nvm 全名 Node Version Manager&#xff0c;Node的版本管理工具 NVM能做什么&#xff1f; 安装 nvm 后&#xff0c;可以使用nvm的相关命令来管理和切换不同的 node 版本&#xff0c;方便开发 如何安装NVM 链接: NVM GitHub地址 如何使用 NVM 命令 …

R语言绘制PCA双标图

代码&#xff1a; setwd("D:/Desktop/0000/R") #更改路径#导入数据 df <- read.table("Input data.csv", header T, sep ",")# ----------------------------------- #所需的包: packages <- c("ggplot2", "tidyr"…

1.简单工厂模式

UML类图 代码 main.cpp #include <iostream> #include "OperationFactory.h" using namespace std;int main(void) {float num1;float num2;char operate;cin >> num1 >> num2 >> operate;Operation* oper OperationFactory::createOpera…

算法综合篇专题四:前缀和

"回忆里的我&#xff0c;比国王富有。奢侈的快乐~" 1、前缀和【模板】 (1) 题目解析 (2) 算法原理 #include <iostream> using namespace std;const int N 100010; // 可能出现溢出 long long arr[N],dp[N]; int n,q;int main() {cin >> n …

长胜证券:突破五日线什么意思?

随着股市的快速开展&#xff0c;越来越多的人开端了解和参与股票投资&#xff0c;但或许会遇到一些术语和概念&#xff0c;例如“打破五日线”&#xff0c;这是新手们需求了解的。本文将介绍“打破五日线”的概念及其意义&#xff0c;同时从不同视点剖析其意义和影响因素。 什…

记录wisemodel上传失败

参考&#xff1a;https://wisemodel.cn/docs/%E6%A8%A1%E5%9E%8B%E4%B8%8A%E4%BC%A0 第一种方法&#xff1a; git lfs install git clone https://oauth2:your_git_tokenwww.wisemodel.cn/username/my_test_model.git也就是用oauth2&#xff0c;然后再按照一般的方法传文件&a…

(三十三)大数据实战——Canal安装部署及其应用案例实战

前言 Canal 是一个开源的MySQL数据库binlog监听和解析框架&#xff0c;用于实时捕获 MySQL数据库的binlog 变更事件&#xff0c;并将其解析成易于消费的数据格式。Canal 可以实时监听 MySQL 数据库的 binlog&#xff0c;并即时捕获数据库的数据变更事件。Canal可以将捕获到的b…

C++ function<>和bind()

一、可调用对象 介绍两个概念&#xff1a;调用运算符和可调用对象 调用运算符 调用运算符&#xff0c;即&#xff1a;() 。跟随在函数名之后的一对括号 “()”&#xff0c;起到调用函数的效果&#xff0c;传递给函数的参数放置在括号内。 可调用对象 对于一个对象或者一个表…

位图+布隆过滤器+海量数据问题(它们都是哈希的应用)

一)位图: 首先计算一下存储一下10亿个整形数据&#xff0c;需要多大内存呢&#xff0c;多少个G呢&#xff1f; 2^3010亿&#xff0c;10亿个字节 byte kb mb gb 100000000个字节/1024/1024/10241G 所以10亿个字节就是1G&#xff0c;所以40亿个字节就是4G&#xff0c;也就是10个整…

Swing基本组件的用法(一)

语雀笔记&#xff1a;https://www.yuque.com/huangzhanqi/rhwoir/paaoghdyv0tgksk1https://www.yuque.com/huangzhanqi/rhwoir/paaoghdyv0tgksk1Java图形化界面: Java图形化界面学习demo与资料 (gitee.com)https://gitee.com/zhanqi214/java-graphical-interface Swing组件层次…

机器学习笔记 - 视频分析和人类活动识别技术路线简述

一、理解人类活动识别 首先了解什么是人类活动识别,简而言之,是对某人正在执行的活动/动作进行分类或预测的任务称为活动识别。 我们可能会有一个问题:这与普通的分类任务有什么不同?这里的问题是,在人类活动识别中,您实际上需要一系列数据点来预测正确执行的动作。 看看…

Python 多进程异常

这里写目录标题 1、捕获异常2、退出程序3、进程共享变量4、multiprocessing的Pool所起的进程中再起进程 1、捕获异常 https://zhuanlan.zhihu.com/p/321408784 try:<语句> except Exception as e:print(异常说明,e)1 捕获所有异常 包括键盘中断和程序退出请求&#xff0…

一个Binder的前生今世 (一):Service的创建

一个Binder的前生今世 (一):Service的创建 一个Binder的前生今世Binder的历史 (字面意义的前生今世)Binder的生命周期(抽象意义的前生今世)Binder 应用及系统层关系图Binder应用层的架构设计Binder应用层实现Binder的创建服务端Binder的创建服务端Binder的传递Binder在客…

Trino HTTPS 与密码认证介绍与实战操作

文章目录 一、概述二、安装 Trino三、配置 HTTPS1&#xff09;生成证书2&#xff09;配置 Trino3&#xff09;修改 Trino docker-compose yaml 文件4&#xff09;开始部署 Trino5&#xff09;测试验证 四、密码认证1&#xff09;开启密码认证2&#xff09;创建密码认证配置文件…

AndroidStudio 安装与配置【安装教程】

1.下载软件 进入官网https://developer.android.google.cn/studio&#xff0c;直接点击下载 2.阅读并同意协议书 直接下滑至最底部 如果这里出现了无法访问 官方地址&#xff1a;https://redirector.gvt1.com/edgedl/android/studio/install/2022.3.1.19/android-studio-2022.…

java:杨辉三角形

public class YangHui {public static void main(String[] args){int yangHui[][] new int[10][];for (int i 0; i < yangHui.length;i){yangHui[i] new int[i 1];for (int j 0; j < yangHui[i].length; j){ // 最初和最后的数值都是1if (j 0 || j …

LeetCode 847. Shortest Path Visiting All Nodes【状态压缩,BFS;动态规划,最短路】2200

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…