[力扣算法刷题学习]7. 整数反转 8. 字符串转换整数 (atoi)

文章讲述了两个编程问题的解决方案:一是如何反转一个32位有符号整数的数字部分,同时处理可能的溢出情况;二是实现一个类似于C/C++的atoi函数,将字符串转换为32位有符号整数,处理正负号、溢出和非数字字符的问题。文中给出了不同解法,包括作者的答案和官方解答。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

7. 整数反转

问题

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

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

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

示例 1:

输入:x = 123
输出:321

示例 2:

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

示例 3:

输入:x = 120
输出:21

示例 4:

输入:x = 0
输出:0

提示:

-231 <= x <= 231 - 1

我的答案

public int reverse(int x) {
		// 判断正负,取出符号位
        int flag = x >= 0 ? 1 : -1;
        // 取正数结果
        x = x >= 0 ? x : -x;
        long result = 0L;
        // 进行运算,求的结果
        while (x > 0) {
            result = result * 10 + x % 10;
            x /= 10;
        }
        // 判断是否越界
        if (result*flag > Integer.MAX_VALUE || result*flag < Integer.MIN_VALUE) {
            return 0;
        }
        // 返回结果
        return (int)result * flag;
    }

官方解答

文字解答

在这里插入图片描述
在这里插入图片描述

代码

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;
    }
}

复杂度分析

  • 时间复杂度:O(log⁡∣x∣)O(log⁡∣x∣)O(logx)。翻转的次数即 xxx 十进制的位数。

  • 空间复杂度:O(1)O(1)O(1)

网友解答

可以直接存一个临时的翻转结果,如果这个翻转结果除以10不等于上一个结果,说明有溢出。 这种做法相对简洁易懂一些。这个方法仅限Java

代码

public int reverse(int x) {
	int res = 0;
	 while (x != 0) {
	     int tmp = res * 10 + x % 10;
	     if (tmp / 10 != res) { // 溢出!!!
	         return 0;
	     }
	     res = tmp;
	     x /= 10;
	 }
	 return res;
}

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

问题

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

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

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

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我的解答

public int myAtoi(String s) {
	// 去除左右空字符
    s = s.trim();
    // 若为空串则返回0
    if (s.length() == 0)
        return 0;
    // 拼接字符串
    StringBuffer sb = new StringBuffer();
    // 默认拼接0
    sb.append(0);
    // 声明符号位
    int flag = 1;
    // 若为 + 或 - 则取出并赋值符号位
    if (s.charAt(0) == '-'){
        flag = -1;
        s = s.substring(1);
    }else if(s.charAt(0) == '+') {
        s = s.substring(1);
    }
    // 取出数字
    for (int i = 0; i < s.length(); i++) {
    	// 若不为数字则退出循环
        if (s.charAt(i) < 48 || s.charAt(i) > 57) {
            break;
        }
        sb.append(s.charAt(i));
    }
    // 取出结果字符串
    String resultStr = sb.toString();
    // 定义数字结果
    int result;
    try {
    	// 将结果字符串转为数字
        result = Integer.parseInt(resultStr);
    } catch (NumberFormatException e) {
    	// 越界报异常,返回int类型边界值
        return flag == 1? Integer.MAX_VALUE : Integer.MIN_VALUE;
    }
    // 若无异常则返回数字结果
    return result* flag;
}

官方解答

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码

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;
    }
}

在这里插入图片描述

<think>好的,用户问的是C语言在力扣时常见的字符串操作有哪些,以及如何实现。首先,我需要回忆一下常见的字符串目类型,比如反转字符串、回文检查、字符串转换、子串查找等。然后,针对每个类型,我需要给出对应的实现方法,可能还需要注意C语言的特性,比如字符串以'\0'结尾,使用字符数组等。 用户可能是在准备面试或者,所以需要简洁明了的总结,以及示例代码。同时,用户可能希望了解不同操作的时间复杂度和注意事项,比如内存管理、指针使用是否正确等。此外,用户可能还希望知道一些常见错误,比如越界访问、忘记分配内存等。 接下来,我需要分点列出常见的字符串操作,每个操作给出简要说明和示例代码。例如,反转字符串可以用双指针,回文检查也是类似。字符串转换可能涉及库函数如atoi,或者手动实现。子串查找可以用滑动窗口或者KMP算法。还要注意动态内存分配,比如使用malloc和free,避免内存泄漏。 另外,用户之前的问是关于内存错误的,所以在回答这个问时,可能需要强调在C语言中处理字符串时常见的错误点,比如未分配足够的内存、忘记添加结束符'\0'等。同时,给出一些相关问作为扩展,帮助用户进一步练习。 需要确保示例代码正确,比如反转字符串的函数参数是否正确传递,是否有越界的风险。例如,反转字符串时,交换两个字符,中间变量的使用是否正确,指针移动是否正确。 可能还需要提到一些力扣相关的技巧,比如如何处理输入输出,如何优化时间复杂度等。例如,使用哈希表来处理字符频率统计,或者双指针技巧处理子串问。 最后,整理出相关问,帮助用户巩固每个知识点。比如,如何判断两个字符串是否为异位词,如何实现字符串的左旋操作等。 </think>在C语言中,字符串操作是高频考点,常见操作及实现如下: --- ### 1. **字符串反转** ```c void reverseString(char* s, int sSize) { int left = 0, right = sSize - 1; while (left < right) { char tmp = s[left]; s[left] = s[right]; s[right] = tmp; left++; right--; } } ``` **注意**:输入参数是字符数组和长度,需交换字符直到中间位置。 --- ### 2. **判断回文字符串** ```c bool isPalindrome(char* s, int len) { int left = 0, right = len - 1; while (left < right) { if (s[left++] != s[right--]) return false; } return true; } ``` **注意**:忽略非字母数字字符时需先过滤(如力扣125)。 --- ### 3. **字符串整数atoi)** ```c int myAtoi(char* str) { int i = 0, sign = 1, result = 0; // 跳过空格 while (str[i] == ' ') i++; // 处理符号 if (str[i] == '-' || str[i] == '+') { sign = (str[i++] == '-') ? -1 : 1; } // 转换数字 while (isdigit(str[i])) { int digit = str[i++] - '0'; // 溢出处理 if (result > INT_MAX / 10 || (result == INT_MAX / 10 && digit > INT_MAX % 10)) { return (sign == 1) ? INT_MAX : INT_MIN; } result = result * 10 + digit; } return result * sign; } ``` **注意**:需处理前导空格、符号、溢出边界条件。 --- ### 4. **查找最长公共前缀** ```c char* longestCommonPrefix(char** strs, int strsSize) { if (strsSize == 0) return ""; char* prefix = strs[0]; for (int i = 1; i < strsSize; i++) { int j = 0; while (prefix[j] && strs[i][j] && prefix[j] == strs[i][j]) j++; prefix[j] = '\0'; if (j == 0) break; } return prefix; } ``` **注意**:逐个字符比较,逐步缩短公共前缀。 --- ### 5. **子串查找(KMP算法)** ```c // 构建部分匹配表(LPS数组) void computeLPS(char* pattern, int* lps) { int len = 0, i = 1; lps[0] = 0; while (i < strlen(pattern)) { if (pattern[i] == pattern[len]) { len++; lps[i++] = len; } else { if (len != 0) len = lps[len - 1]; else lps[i++] = 0; } } } // KMP主函数 int kmpSearch(char* text, char* pattern) { int M = strlen(pattern), N = strlen(text); int lps[M]; computeLPS(pattern, lps); int i = 0, j = 0; while (i < N) { if (pattern[j] == text[i]) { i++; j++; } if (j == M) return i - j; // 找到匹配 else if (i < N && pattern[j] != text[i]) { if (j != 0) j = lps[j - 1]; else i++; } } return -1; // 未找到 } ``` **注意**:KMP算法时间复杂度O(N+M),优于暴力解法O(N*M)。 --- ### 6. **字符串分割(strtok模拟)** ```c char** splitString(char* str, char* delimiters, int* returnSize) { char* token = strtok(str, delimiters); char** result = (char**)malloc(100 * sizeof(char*)); int idx = 0; while (token != NULL) { result[idx++] = strdup(token); // 复制子串 token = strtok(NULL, delimiters); } *returnSize = idx; return result; } ``` **注意**:`strtok`会修改原字符串,需用`strdup`保存子串。 --- ### 常见错误与优化 1. **内存泄漏**:手动分配内存后需及时释放(如`strdup`返回的指针)。 2. **越界访问**:检查字符串长度(如`strlen`不包含`\0`)。 3. **忽略大小写**:比较时需统一转换(如`tolower`函数)。 4. **暴力解法优化**:滑动窗口(如力扣3最长无重复子串)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值