资质老袁 發表於 2025-12-11 09:00:00

剑指offer-49、把字符串转换成整数

<h2 id="题描述">题⽬描述</h2>
<p>请你来实现⼀个 myAtoi(string s) 函数,使其能将字符串转换成⼀个 32 位有符号整数(类似C/C++ 中的 atoi 函数)。</p>
<p>函数 myAtoi(string s) 的算法如下:</p>
<ul>
<li>读⼊字符串并丢弃⽆⽤的前导空格</li>
<li>检查下⼀个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数,还是正数。 如果两者都不存在,则假定结果为正。</li>
<li>读⼊下⼀个字符,直到到达下⼀个⾮数字字符或到达输⼊的结尾。字符串的其余部分将被忽略。</li>
<li>将前⾯步骤读⼊的这些数字转换为整数(即," 123 " -&gt; 123 , " 0032 " -&gt; 32 )。</li>
<li>如果没有读⼊数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。</li>
<li>如果整数数超过 32 位有符号整数范围 [−2^31, 2^(31 − 1)] ,需要截断这个整数,使其保持在这个范围内。具体来说,⼩于 −2^31 的整数应该被固定为 2^31 ,⼤于 2^(31 − 1) 的整数应该被固定为2^(31 − 1)</li>
<li>返回整数作为最终结果。</li>
</ul>
<p>注意:</p>
<ul>
<li>本题中的空⽩字符只包括空格字符 ' ' 。</li>
<li>除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。</li>
</ul>
<p>示例1:<br>
输⼊:s = "42"<br>
输出:42<br>
解释:加粗的字符串为已经读⼊的字符,插⼊符号是当前读取的字符。</p>
<ol>
<li>第 1 步:"42"(当前没有读⼊字符,因为没有前导空格)</li>
<li>第 2 步:"42"(当前没有读⼊字符,因为这⾥不存在 '-' 或者 '+')</li>
<li>第 3 步:"42"(读⼊ "42")</li>
<li>解析得到整数 42 。</li>
<li>由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。</li>
</ol>
<p>示例2:<br>
输⼊:s = " -42"<br>
输出:-42<br>
解释:</p>
<ol>
<li>第 1 步:" -42"(读⼊前导空格,但忽视掉)</li>
<li>第 2 步:" -42"(读⼊ '-' 字符,所以结果应该是负数)</li>
<li>第 3 步:" -42"(读⼊ "42")</li>
<li>解析得到整数 -42 。</li>
<li>由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。</li>
</ol>
<p>示例3:<br>
输⼊:s = "4193 with words"<br>
输出:4193<br>
解释:</p>
<ol>
<li>第 1 步:"4193 with words"(当前没有读⼊字符,因为没有前导空格)</li>
<li>第 2 步:"4193 with words"(当前没有读⼊字符,因为这⾥不存在 '-' 或者 '+')</li>
<li>第 3 步:"4193 with words"(读⼊ "4193";由于下⼀个字符不是⼀个数字,所以读⼊停⽌)</li>
<li>解析得到整数 4193 。</li>
<li>由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。</li>
</ol>
<p>示例4:<br>
输⼊:s = "words and 987"<br>
输出:0<br>
解释:</p>
<ol>
<li>第 1 步:"words and 987"(当前没有读⼊字符,因为没有前导空格)</li>
<li>第 2 步:"words and 987"(当前没有读⼊字符,因为这⾥不存在 '-' 或者 '+')</li>
<li>第 3 步:"words and 987"(由于当前字符 'w' 不是⼀个数字,所以读⼊停⽌)</li>
<li>解析得到整数 0 ,因为没有读⼊任何数字。</li>
<li>由于 0 在范围 [-231, 231 - 1] 内,最终结果为 0 。</li>
</ol>
<p>示例5:<br>
输⼊:s = "-91283472332"<br>
输出:-2147483648<br>
解释:</p>
<ol>
<li>第 1 步:"-91283472332"(当前没有读⼊字符,因为没有前导空格)</li>
<li>第 2 步:"-91283472332"(读⼊ '-' 字符,所以结果应该是负数)</li>
<li>第 3 步:"-91283472332"(读⼊ "91283472332")</li>
<li>解析得到整数 -91283472332 。</li>
<li>由于 -91283472332 ⼩于范围 [-231, 231 - 1] 的下界,最终结果被截断为 -231 = -2147483648</li>
</ol>
<p>提示:</p>
<ul>
<li>0 &lt;= s.length &lt;= 200</li>
<li>s 由英⽂字⺟(⼤写和⼩写)、数字(0-9)、' '、'+'、'-' 和 '.' 组成</li>
</ul>
<h2 id="思路与解答">思路与解答</h2>
<h3 id="基础遍历法">基础遍历法</h3>
<p>这道题⽬看起来很⻓,但是实际上逻辑很清晰,就是将字符串解析成为数字,⾥⾯有⼏个特殊的则:</p>
<ol>
<li>前⾯的空格去掉,不读取</li>
<li>接下来的字符必须是数字,“ + ”号或者“ - ”号
<ol>
<li>如果是“ + ”号或者“ - ”号,将符号记录下来</li>
<li>没有符号默认是“ + ”号,正数。</li>
</ol>
</li>
<li>接下来的字符必须是数字,遇到其他字符会直接结束</li>
<li>需要考虑溢出的问题</li>
</ol>
<p>在将字符串转换成数字的时候,⽤下⾯这句核⼼代码:</p>
<pre><code class="language-java">sum = sum * 10 + (str.charAt(i) - '0');
</code></pre>
<p>但是在这个过程中,我们依然需要考虑数字溢出的问题,针对这种情况,我们可以在加和之前判断,针对⼤于0的情况,如果⼤于最⼤值整除10,或者等于最⼤值整除10,但是个位数超过了,都直接返回0。</p>
<p>假设最⼤值是127,那么sum如果⼤于12,肯定会超过,如果sum == 12,但是个位数⼤于7,乘以10相加,也肯定会超。</p>
<pre><code class="language-java">if (sum &gt; Integer.MAX_VALUE/10 || (sum == Integer.MAX_VALUE / 10 &amp;&amp;
(str.charAt(i) - '0') &gt; 7)) return 0;
</code></pre>
<p>对于⼩于0 的情况,假设最⼩值是-128 ,那么sum 是数字部分 128 , 如果当前sum ⼤于 12 ,那么就⼀定超出,或者sum == 12 ,但是个位数⼤于8 ,乘以10 ,相加也会⼤于128 ,不符合要求,所以直接返回0 。</p>
<pre><code class="language-java">if (sum &lt; Integer.MIN_VALUE/10 || (sum == Integer.MIN_VALUE / 10 &amp;&amp; x
(str.charAt(i) - '0') &gt; 8)) return 0;
</code></pre>
<p>具体代码实现:</p>
<pre><code class="language-java">public class Solution {
    public static int myAtoi(String str) {
      if (str == null) {
            return 0;
      }
      int i = 0;
      while (i &lt; str.length() &amp;&amp; str.charAt(i) == ' ') {
            i++;
      }
      if (i &gt;= str.length() || (str.charAt(i) != '-' &amp;&amp; str.charAt(i) != '+' &amp;&amp; !((str.charAt(i) &gt;= '0') &amp;&amp;
                (str.charAt(i) &lt;= '9')))) {
            return 0;
      }
      int sign = 1;
      if (i &lt; str.length() &amp;&amp; (str.charAt(i) == '-' || i &lt; str.length() &amp;&amp;
                str.charAt(i) == '+')) {
            sign = str.charAt(i) == '-' ? -1 : 1;
            i++;
      }
      int sum = 0;
      for (; i &lt; str.length(); i++) {
            if (str.charAt(i) &gt;= '0' &amp;&amp; str.charAt(i) &lt;= '9') {
                if (sign == 1) {
                  if (sum &gt; Integer.MAX_VALUE / 10 || sum == Integer.MAX_VALUE / 10 &amp;&amp; (str.charAt(i) - '0') &gt; 7) {
                        return Integer.MAX_VALUE;
                  }
                } else {
                  if (sum &gt; (Integer.MAX_VALUE) / 10 || sum ==
                        (Integer.MAX_VALUE) / 10 &amp;&amp; (str.charAt(i) - '0') &gt; 8) {
                        return Integer.MIN_VALUE;
                  }
                }
                sum = sum * 10 + (str.charAt(i) - '0');
            } else {
                return sum * sign;
            }
      }
      return sum * sign;
    }
}
</code></pre>
<ul>
<li>时间复杂度为 O(n)</li>
<li>空间复杂度为 O(1)。</li>
</ul>
<h3 id="正则表达式">正则表达式</h3>
<p>使用正则表达式来匹配数字模式,代码更加简洁</p>
<pre><code class="language-java">public class Solution {
    public int myAtoi(String s) {
      if (s == null) return 0;
      
      s = s.trim();
      if (s.length() == 0) return 0;
      
      // 使用正则表达式匹配数字模式:可选符号位+数字(@ref)
      Pattern pattern = Pattern.compile("^[+-]?\\d+");
      Matcher matcher = pattern.matcher(s);
      
      if (!matcher.find()) {
            return 0; // 没有匹配到数字模式
      }
      
      String numStr = matcher.group();
      int sign = 1;
      int startIndex = 0;
      
      // 处理符号位
      if (numStr.charAt(0) == '+') {
            startIndex = 1;
      } else if (numStr.charAt(0) == '-') {
            sign = -1;
            startIndex = 1;
      }
      
      long result = 0; // 使用long防止转换过程中溢出
      
      // 转换数字部分
      for (int i = startIndex; i &lt; numStr.length(); i++) {
            int digit = numStr.charAt(i) - '0';
            result = result * 10 + digit;
            
            // 检查是否溢出int范围
            if (sign == 1 &amp;&amp; result &gt; Integer.MAX_VALUE) {
                return Integer.MAX_VALUE;
            }
            if (sign == -1 &amp;&amp; -result &lt; Integer.MIN_VALUE) {
                return Integer.MIN_VALUE;
            }
      }
      
      return (int) result * sign;
    }
}
</code></pre>
<ul>
<li><strong>时间复杂度</strong>:O(n),正则匹配和数字转换都是线性时间</li>
<li><strong>空间复杂度</strong>:O(n),需要存储匹配到的子字符串</li>
</ul>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自在线网站:seven的菜鸟成长之路,作者:seven,转载请注明原文链接:www.seven97.top</p><br><br>
来源:https://www.cnblogs.com/sevencoding/p/19316233
頁: [1]
查看完整版本: 剑指offer-49、把字符串转换成整数