力扣算法练习(三)

news2024/12/23 20:47:18

目录

1. N 字形变换(6)

题解一(力扣官方解析力扣)

题解二(官方解法)

题解三(力扣)

2. 整数反转(7)

题解一

题解二

题解三(官方解析,与第一种类似)

3.字符串转换整数 (atoi)(8)

题解一

题解二

题解三(最优解)

题解四


1. N 字形变换(6)

将一个给定字符串 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"

题解一(力扣官方解析力扣)

class Solution {
    public String convert(String s, int numRows) {
        int n = s.length(), r = numRows;
        if (r == 1 || r >= n) {
            return s;
        }
        int t = r * 2 - 2;
        int c = (n + t - 1) / t * (r - 1);
        char[][] mat = new char[r][c];
        for (int i = 0, x = 0, y = 0; i < n; ++i) {
            mat[x][y] = s.charAt(i);
            if (i % t < r - 1) {
                ++x; // 向下移动
            } else {
                --x;
                ++y; // 向右上移动
            }
        }
        StringBuffer ans = new StringBuffer();
        for (char[] row : mat) {
            for (char ch : row) {
                if (ch != 0) {
                    ans.append(ch);
                }
            }
        }
        return ans.toString();
    }
}

题解二(官方解法)

方法一中的矩阵有大量的空间没有被使用,能否优化呢?

注意到每次往矩阵的某一行添加字符时,都会添加到该行上一个字符的右侧,且最后组成答案时只会用到每行的非空字符。因此我们可以将矩阵的每行初始化为一个空列表,每次向某一行添加字符时,添加到该行的列表末尾即可。

 

class Solution {
    public String convert(String s, int numRows) {
        int n = s.length(), r = numRows;
        if (r == 1 || r >= n) {
            return s;
        }
        StringBuffer[] mat = new StringBuffer[r];
        for (int i = 0; i < r; ++i) {
            mat[i] = new StringBuffer();
        }
        for (int i = 0, x = 0, t = r * 2 - 2; i < n; ++i) {
            mat[x].append(s.charAt(i));
            if (i % t < r - 1) {
                ++x;
            } else {
                --x;
            }
        }
        StringBuffer ans = new StringBuffer();
        for (StringBuffer row : mat) {
            ans.append(row);
        }
        return ans.toString();
    }
}

题解三(力扣)

这是k神的解法,只能说看完以后,直接佩服,用字符缓冲区完美的解决了这个问题,我真的有点惯性思维了,第一时间只想到了二维数组。没想到用字符缓冲区。还有flag用的很妙。

class Solution {
    public String convert(String s, int numRows) {
        if(numRows < 2) return s;
        List<StringBuilder> rows = new ArrayList<StringBuilder>();
        for(int i = 0; i < numRows; i++) rows.add(new StringBuilder());
        int i = 0, flag = -1;
        for(char c : s.toCharArray()) {
            rows.get(i).append(c);
            if(i == 0 || i == numRows -1) flag = - flag;
            i += flag;
        }
        StringBuilder res = new StringBuilder();
        for(StringBuilder row : rows) res.append(row);
        return res.toString();
    }
}

2. 整数反转(7)

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:

输入:x = 123
输出:321

示例 2:

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

示例 3:

输入:x = 120
输出:21

题解一

每次取末尾数字,拼成一个新的。(参考自力扣)判断条件,因为x本身会被int限制,当x为正数并且位数和Integer.MAX_VALUE的位数相等时首位最大只能为2,所以逆转后不会出现

res = Integer.MAX_VALUE / 10 && tmp > 2的情况,自然也不需要判断res==214748364 && tmp>7了,反之负数情况也一样

class Solution {
    public int reverse(int x) {
        int res = 0;
        while(x!=0) {
            //每次取末尾数字
            int tmp = x%10;
            //判断是否 大于 最大32位整数
        if (res > Integer.MAX_VALUE / 10 || res < Integer.MIN_VALUE / 10)  {
            return 0;
        }
            res = res*10 + tmp;
            x /= 10;
        }
        return res;
    }
}	

题解二

先转成string,再转成char,然后先判断符号,再循环首尾交换。处理异常。

class Solution {
    public int reverse(int x) {
        String s=String.valueOf(x);
        char[] array=s.toCharArray();
        int i=0,right=s.length()-1;
        char temp=' ';
        if(s.charAt(i)=='+'||s.charAt(i)=='-'){
            i++;
        }
        while(i<right){
            temp=array[i];
            array[i]=array[right];
            array[right]=temp;
            i++;
            right--;
        }
        try{
            return Integer.parseInt(String.valueOf(array));
        }catch(NumberFormatException e){
            return 0;
        }
    }
}

题解三(官方解析,与第一种类似)

参考力扣

记rev 为翻转后的数字,为完成翻转,我们可以重复「弹出」xxx 的末尾数字,将其「推入」rev 的末尾,直至 xxx 为 000。

要在没有辅助栈或数组的帮助下「弹出」和「推入」数字,我们可以使用如下数学方法:

// 弹出 x 的末尾数字 digit
digit = x % 10
x /= 10

// 将数字 digit 推入 rev 末尾
rev = rev * 10 + digit

class Solution {
    public int reverse(int x) {
        int rev = 0;
        while (x != 0) {
            if (rev < Integer.MIN_VALUE / 10 || rev > Integer.MAX_VALUE / 10) {
                return 0;
            }
            int digit = x % 10;
            x /= 10;
            rev = rev * 10 + digit;
        }
        return rev;
    }
}

3.字符串转换整数 (atoi)(8)

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

函数 myAtoi(string s) 的算法如下:

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

注意:

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

示例 1:

输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"42"(读入 "42")
           ^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。

示例 2:

输入:s = "   -42"
输出:-42
解释:
第 1 步:"   -42"(读入前导空格,但忽视掉)
            ^
第 2 步:"   -42"(读入 '-' 字符,所以结果应该是负数)
             ^
第 3 步:"   -42"(读入 "42")
               ^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。

示例 3:

输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
             ^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。

题解一

首先将字符串分割成数组并去掉首部空格,然后遍历,如果第一个为符号,则存入,然后匹配数字,不是数字则break。然后对字符进行异常处理,判断边界和符号。

class Solution {
    public int myAtoi(String s)  {
        int result=0,i=0;
        String[] str=s.trim().split("");//去掉首部空格并分割成字符数组
        String flag="";//正负符号
        StringBuffer newStr=new StringBuffer();//新建一个临时存储区域
        while(i<str.length){
            if(str[i].equals("+")&&i==0||str[i].equals("-")&&i==0){//如果有符号则存储
                flag=str[i];
                i++;
                continue;
            }
            if(str[i].matches("[0-9]+")){//用正则匹配数字
                newStr.append(str[i]);
                i++;
            }else{
                break; 
            }
        }
        try{
            if(!newStr.toString().equals("")){
                if(!flag.equals("")){
                    result=Integer.parseInt(flag+newStr.toString());
                }else{
                    result=Integer.parseInt(newStr.toString());
                }
            }else{
                result=0;
            }
        }catch(NumberFormatException e){
            // System.out.println(e);
            if(flag.equals("-")){//判断范围 处理异常
                result=(int)Math.pow(-2,31);
            }else{
                result=(int)Math.pow(2,31);
            }
        }finally{
            return result;
        }
    }
}

题解二

这个是力扣上的官方解析,算法很好,首先列一个状态表,存入map,再遍历字符串,根据状态分别进行不同的判断。

class Solution {
    public int myAtoi(String str) {
        Automaton automaton = new Automaton();
        int length = str.length();
        for (int i = 0; i < length; ++i) {
            automaton.get(str.charAt(i));
        }
        return (int) (automaton.sign * automaton.ans);
    }
}

class Automaton {
    public int sign = 1;
    public long ans = 0;
    private String state = "start";
    private Map<String, String[]> table = new HashMap<String, String[]>() {{
        put("start", new String[]{"start", "signed", "in_number", "end"});
        put("signed", new String[]{"end", "end", "in_number", "end"});
        put("in_number", new String[]{"end", "end", "in_number", "end"});
        put("end", new String[]{"end", "end", "end", "end"});
    }};

    public void get(char c) {
        state = table.get(state)[get_col(c)];
        if ("in_number".equals(state)) {
            ans = ans * 10 + c - '0';
            ans = sign == 1 ? Math.min(ans, (long) Integer.MAX_VALUE) : Math.min(ans, -(long) Integer.MIN_VALUE);
        } else if ("signed".equals(state)) {
            sign = c == '+' ? 1 : -1;
        }
    }

    private int get_col(char c) {
        if (c == ' ') {
            return 0;
        }
        if (c == '+' || c == '-') {
            return 1;
        }
        if (Character.isDigit(c)) {
            return 2;
        }
        return 3;
    }
}

题解三(最优解)

首先这个方法去除首部空格很巧妙,并且考虑了全是空格的极端情况。

然后判断符号位。紧接着遍历字符串,判断数字,并且判断边界。

public class Solution {

    public int myAtoi(String str) {
        int len = str.length();
        // str.charAt(i) 方法回去检查下标的合法性,一般先转换成字符数组
        char[] charArray = str.toCharArray();

        // 1、去除前导空格
        int index = 0;
        while (index < len && charArray[index] == ' ') {
            index++;
        }

        // 2、如果已经遍历完成(针对极端用例 "      ")
        if (index == len) {
            return 0;
        }

        // 3、如果出现符号字符,仅第 1 个有效,并记录正负
        int sign = 1;
        char firstChar = charArray[index];
        if (firstChar == '+') {
            index++;
        } else if (firstChar == '-') {
            index++;
            sign = -1;
        }

        // 4、将后续出现的数字字符进行转换
        // 不能使用 long 类型,这是题目说的
        int res = 0;
        while (index < len) {
            char currChar = charArray[index];
            // 4.1 先判断不合法的情况
            if (currChar > '9' || currChar < '0') {
                break;
            }

            // 题目中说:环境只能存储 32 位大小的有符号整数,因此,需要提前判:断乘以 10 以后是否越界
            if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && (currChar - '0') > Integer.MAX_VALUE % 10)) {
                return Integer.MAX_VALUE;
            }
            if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && (currChar - '0') > -(Integer.MIN_VALUE % 10))) {
                return Integer.MIN_VALUE;
            }

            // 4.2 合法的情况下,才考虑转换,每一步都把符号位乘进去
            res = res * 10 + sign * (currChar - '0');
            index++;
        }
        return res;
    }

}

题解四

我的看法是不如解法三更加容易理解。效率与解法三一致。

public class Solution {

   public int myAtoi(String str) {
        int result = 0;
        boolean negative = false;
        int i = 0, len = str.length();
        int limit = -Integer.MAX_VALUE;
        int multmin;
        int digit;

        //skip space before string
        while (i < len) {
            if (str.charAt(i) == ' ') {
                i++;
            } else {
                break;
            }
        }

        if (i < len) {
            char firstChar = str.charAt(i);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+') {
                    return 0;
                }

                i++;

                if (len == i) {
                    return 0;
                }
            }

            multmin = limit / 10;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(str.charAt(i++), 10);
                if (digit < 0) {
                    return negative ? result : -result;
                }
                if (result < multmin) {
                    return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
                }
                result *= 10;
                if (result < limit + digit) {
                    return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
                }
                result -= digit;
            }
        } else {
            return 0;
        }

        return negative ? result : -result;
    }

}

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

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

相关文章

车辆在刹车不及时导致与行人发生碰撞事故,产生出险记录

车辆在刹车不及时导致与行人发生碰撞事故&#xff0c;是一种常见的交通事故。当发生此类事故时&#xff0c;车主需要及时处理保险理赔事宜&#xff0c;同时也需要了解车辆出险、理赔、事故记录情况&#xff0c;以便更好地维护车辆和自身权益。为方便车主查询车辆出险、理赔、事…

UI自动化测试工具能够做的几件事情

UI自动化测试工具在软件开发过程中发挥着重要的作用。它们可以帮助测试人员自动执行各种用户界面操作&#xff0c;验证界面功能和性能&#xff0c;提高测试效率和质量。本文将介绍UI自动化测试工具能够做的几件事情&#xff0c;并解释为什么它们对测试人员来说非常有价值。 首先…

UE5 plugin failed to load because module could not be found

解决方法&#xff1a;将提示缺少的插件加入到.uproject中即可解决

Liunx系统编程:系统层面上的文件IO接口

目录 一. 如何在系统层面上理解文件 二. 语言层面上的文件IO函数 三. Linux操作系统提供的IO接口 3.1 open接口 -- 打开文件 3.2 close接口 -- 关闭文件 3.3 write接口 -- 向文件中写内容 3.4 read接口 -- 从文件中读取内容 四. 总结 一. 如何在系统层面上理解文件 在L…

axios文件上传和 Content-Type类型介绍

Content-Type的作用是什么&#xff1f; Content-Type: 用于在请求头部指定资源的类型和字符编码。 请求头中的content-type&#xff0c;就是 B端发给S端的数据类型描述 。 即告诉服务器端&#xff0c;我给你传的数据是某种类型的。 服务器端针对不同类型的数据&#xff0c;做法…

分布式监控Zabbix的部署

zabbix 6.0 一、zabbinxzabbix的简介Zabbix 6.0 功能组件zabbix的监控原理zabbix 6.0的特性 二、zabbix 6.0 部署部署 Nginx PHP 环境并测试部署数据库&#xff0c;要求 MySQL 5.7 或 Mariadb 10.5 及以上版本编译安装 zabbix Server 服务端部署 Web 前端&#xff0c;进行访问…

HTTP的一些概念

文章目录 HTTP定义URI&URL HTTP 常见的状态码http 首部请求首部字段响应首部字段为cookie服务的首部字段get请求和post请求及区别GET 和 POST 方法是否安全和幂等 HTTP特性HTTP&#xff08;1.1&#xff09; 的优点有哪些HTTP/1.1 的缺点HTTP/1.1 的性能HTTP/1.1 相比 HTTP/…

[MySQL]表的操作

[MySQL]表的操作 文章目录 [MySQL]表的操作1. 创建表2. 创建表的示例3. 查看表4. 修改表5. 删除表6. 关于表操作 1. 创建表 语法&#xff1a; CREATE TABLE [IF NOT EXISTS] table_name(field1 datatype1 [COMMENT 注释信息],field2 datatype2 [COMMENT 注释信息],field3 dat…

伦敦金实时报价技术分析

技术分析是从伦敦金的价格行为&#xff0c;来分析未来走势变化的方法。伦敦金市场的变化可以有多种表现形式&#xff0c;其中根据市场价格、成交量等的变化&#xff0c;可以探索出一些规律&#xff0c;技术分析者通过对市场过去和现在的行为&#xff0c;应用数学原理去理解价格…

【Python】基于Python的机器学习分类的模型选择:交叉验证和模型质量评估

目录 1 简介2 思路分解与说明3 完整代码 1 简介 最近完成一个工作&#xff0c;就基于一些表格化的数据进行机器学习分类。 由于分类是研究中的关键步骤&#xff0c;所以首先要选择到底哪个模型适合我们的分类任务。 比较传统且经典的选择方法就是用交叉验证。 交叉验证是什么可…

openwrt使用记录

背景&#xff1a; 平时在vmware中做实验时候&#xff0c;经常需要在不同的机器上下载一些github上的项目进行调试&#xff0c;之前解决方案是在路由器层小米ac2100上装openwrt&#xff0c;试用一番发现太卡了。放弃&#xff0c;这次在vmware中安装作为小米ac2100的旁路由 规划…

推荐五款优秀,可替代商业软件的开源软件

​ 在日常的使用中&#xff0c;我们需要使用各种软件来提高我们的工作效率或者进行创意的表达。然而&#xff0c;商业软件价格昂贵&#xff0c;某些国产软件又充斥着广告。因此&#xff0c;开源软件成为了一个不错的选择&#xff0c;以下是我推荐的五款优秀的开源软件。 图片浏…

一文get,最容易碰上的接口自动化测试问题汇总

本篇文章分享几个接口自动化用例编写过程遇到的问题总结&#xff0c;希望能对初次探索接口自动化测试的小伙伴们解决问题上提供一小部分思路。 sql语句内容出现错误 空格&#xff1a;由于有些字段判断是变量&#xff0c;需要将sql拼接起来&#xff0c;但是在拼接字符串时没有…

手写操作系统--完善内核加载器之内存检测

这一篇我们来完善内核加载器的功能&#xff0c;我们知道内存是很重要的区域&#xff0c;我们需要对内存有个大致的描述&#xff0c;哪些可用&#xff0c;那些不可用&#xff0c;内存有多大。因此在内核加载器中我们需要对内存进行检测。内存检测的方法翻译文档如下&#xff1a;…

DAY39:贪心算法(八)无重叠区间+划分字母区间+合并区间

文章目录 435.无重叠区间思路完整版注意点 右区间排序 763.划分字母区间思路完整版如何确定区间分界线debug测试时间复杂度 总结 56.合并区间思路最开始的写法&#xff1a;直接在原数组上修改debug测试 修改版时间复杂度总结 435.无重叠区间 给定一个区间的集合 intervals &am…

“钓鱼”网站也有https?如何一招识破?

作为企业网站安全建设的基础设施&#xff0c; SSL证书可以对数据进行加密传输&#xff0c;保护数据在传输过程中不被监听、截取和篡改&#xff0c;因此部署了SSL证书的网站会比传统的http协议更加安全&#xff0c;也更受主流操作系统和浏览器的信任。 然而随着SSL证书的普及&a…

AI做PPT,五分钟搞定别人一天的量,最喜欢卷PPT了

用AI做PPT 主题生成大纲制作PPT 主题生成大纲 如何使用人工智能工具&#xff0c;如ChatGPT和mindshow&#xff0c;快速生成PPT。 gpt国内版 制作PPT&#xff0c;你可能只有一个主题&#xff0c;但没有明确的提纲或思路。 问gpt&#xff1a;计算机视觉的周工作汇报。我这周学…

MyBatis 与 Hibernate 有哪些不同?

ORM框架的选择与适用场景 MyBatis和Hibernate都是Java领域中流行的面向关系型数据库的ORM&#xff08;对象关系映射&#xff09;框架。它们的共同目标是简化开发人员操作数据库的工作&#xff0c;提供便捷的持久化操作。然而&#xff0c;两者在设计理念和适用场景上有所不同。…

Zabbix6.0 的部署

目录 一、概述 二、 zabbix 1.zabbix简介 2.zabbix监控原理 3. Zabbix 6.0 新特性 3.1Zabbix server高可用防止硬件故障或计划维护期的停机 3.2 Zabbix 6.0 LTS新增Kubernetes监控功能&#xff0c;可以在Kubernetes系统从多个维度采集指标 4. Zabbix 6.0 功能组件 4.1Z…

浏览器内核的介绍

文章目录 1、什么是浏览器内核2、常用浏览器内核3、浏览器内核分类3. 1、Trident3.2、Gecko3.3、Webkit3.4、Chromium3.5、Presto3.6、国内主流浏览器 4、五大主流浏览器&#xff08;诞生顺序&#xff09;4.1、IE&#xff08;Internet Explorer&#xff09;浏览器4.2、Opera浏览…