LeetCodeブラッシングノート08文字列から整数

著者:Ma Zhifeng
リンク:https://zhuanlan.zhihu.com/p/24047577
出典:
著者がほぼ著作権を所有していることを知ってい ます。商用の再版については、著者に連絡して許可を得てください。非商用の再版については、出典を示してください。

リンク

leetcode.com/problems/s

トピック

atoiを実現し、文字列を整数に変換します

言い換えると

この質問の焦点は、考えられる状況を検討することです。

  1. 数字以外の文字の扱い方
  2. 符号
  3. オーバーフロー

もちろん、アイデアは間違いなく文字列内の各文字を処理することです。では、文字「1」を数字の1に変換するにはどうすればよいでしょうか。

シャオマ兄弟はかなり愚かです、私はそれを予期していませんでした

ASCIIテーブルに関係しているのではないかと思いましたが、詳しく調べることができず、ついに答えを覗きました。

あなたは祝福されています、あなたがそれを期待していなければ、あなたはもう答えを読む必要はありません、私はあなたに話します

'1' - '0' = 1;

はい、文字0から減算するだけです。それらはテーブル内で連続しているため

さて、重要な問題は解決しました。いくつかの特殊なケースに対処する方法を見てみましょう。

  1. 数字以外の文字の場合、先頭と末尾の空の文字( "23")は無視できます。数字の途中に他の文字( "123x21")がある場合は、不正な入力と見なされます。
  2. サイン、保存する必要があります
  3. オーバーフロー、前のトピックの方法がまだあります。長い間使用して対処します

補足説明

トピックの補足説明に基づいて、いくつかのテストケースを作成できます。

  1. 「123」→123
  2. 「-123」→-123
  3. 「123x456」→123
  4. 「123456」→123
  5. 「343485894858938553」→INT_MAX
  6. 「」→0
  7. 「xxxyyy」→0

質問をする前に、C ++がサポートする文字操作をプレビューできます。「C ++入門書」第5版(中国語版)P82、表3.3を参照してください。

すべての準備が整いました。正式に問題の解決を開始してください

コード

class Solution {
      
        
public:  
    int myAtoi(string str) {
      
        

        int iFlag = 1;  

        bool bStart = false;  
        vector<int> vecDigits;  

        for( auto c : str )  
        {
      
        
            if( !bStart )  
            {
      
        
               if( isspace(c) )  
                {
      
        
                    continue;  
                }   

                if( ('+' == c || '-' == c ) )  
                {
      
        
                    iFlag = '+' == c ? 1 : -1;  
                    bStart = true;  
                    continue;  
                }  
            }  

            if( isdigit(c) )  
            {
      
        
                bStart = true;  
                vecDigits.push_back( c - '0' );  
            }  
            else  
            {
      
        
                break;  
            }  
        }  

        if( vecDigits.size() == 0 )  
        {
      
        
            return 0;  
        }  

        long long result = 0;  
        long long iFactor = 1;  

        auto i = vecDigits.size();  
        while( i > 0 )  
        {
      
        
            --i;  
            result += iFactor * vecDigits[i];  
            iFactor *= 10;  

            if( result*iFlag > INT_MAX )  
            {
      
        
                return INT_MAX;  
            }  

            if( result*iFlag < INT_MIN )  
            {
      
        
                return INT_MIN;  
            }  
        }  

        return result*iFlag;  
    }  
};

ロジックは少し複雑です。説明させてください。

  1. 最初のforループは、有効な数値をベクトルにプッシュするために使用されます
    • iFlagはサインを保存するために使用されます
    • bStartは、数値がすでに処理されているかどうかを保存するために使用されます。このフラグを追加する理由は、数値の前のスペースと数値の後のスペースの処理が異なるためです。
  2. forループの後、ベクトルがまだ空で、有効な数値がなく、0が直接返される場合
  3. 次のwhileステートメントは、前の質問と同じ方法で整数を取得するために使用されます。オーバーフロー判定は、longlongより長い文字列を回避するためにループ内に配置されます

もちろん、このコードもLeetCodeを渡すために数回変更されています。

次に、上記のロジックを簡略化できるかどうかを見てみましょう。

コードを変更する前に、コードを単純化するときにロジックの正確さをどのように確認するかという質問について考える必要があります。

これは非常に一般的な問題であり、コーディングプロセス中に頻繁に発生します。もともとはコードを担当して完璧を目指していたので、スピードは上がりましたが、結果は良くありませんでした。

この問題を解決するには、「テスト駆動開発」方式、つまりコードの記述を開始する前にテストケースを設計する方法を試すことができます。コードがすべてのテストケースに合格できる場合は、機能要件を満たしています。その後のコード変更を行うときは、すべてのユースケースが成功することを確認する必要があります。ユースケースが失敗した場合は、変更されたコードに問題があることを意味します。

前に書いたユースケースと同じように、もちろんこれらのユースケースは確かに十分ではありませんが、何も書かないよりもはるかに優れています。ご存知のとおり、leetcodeにはこのトピックのテストケースが1047あります。

いくつかの小さなプログラムを書くとき、assertを使用して結果の判断を完了することができます。

//leetcode08.h  

#include <string  

using std::string;  

class Solution08 {  
public:  
    static int myAtoi(string str);  
};
//main  

#include "cassert"  

assert(Solution::myAtoi("123")== 123);  
assert(Solution08::myAtoi("123") == 123);  
assert(Solution08::myAtoi("-123") == -123);  
assert(Solution08::myAtoi("    -123   ") == -123);  
assert(Solution08::myAtoi("    123   456   ") == 123);

上記のテストケースに記入してから、他のシナリオがあるかどうかを検討してください。ある場合は、テストケースの使用にけちをつけないでください。

おすすめ

転載: blog.csdn.net/qq_26751117/article/details/53442419