3131//!
3232//!
3333//! Example 1:
34- //! ```ignore
34+ //! ```plain
3535//! Input: s = "42"
3636//! Output: 42
3737//! Explanation: The underlined characters are what is read in, the caret is the
4747//! ```
4848//!
4949//! Example 2:
50- //! ```ignore
50+ //! ```plain
5151//! Input: s = " -42"
5252//! Output: -42
5353//! Explanation:
6262//! ```
6363//!
6464//! Example 3:
65- //! ```
65+ //! ```plain
6666//! Input: s = "4193 with words"
6767//! Output: 4193
6868//! Explanation:
8989///
9090/// # Argument
9191/// * `s` - input string
92+ ///
93+ /// ```
94+ /// use leetcode_rust::problems::p000_0xx::p000_008::my_atoi;
95+ ///
96+ /// assert!(my_atoi(String::from("-12.5")) == -12);
97+ /// ```
9298pub fn my_atoi ( s : String ) -> i32 {
99+ // Upper bound for possitive i32. The last element should be increased
100+ // if given string indicates a negative i32 (no sign symbol included).
93101 let mut threshold_val: [ u8 ; 10 ] = [ 50 , 49 , 52 , 55 , 52 , 56 , 51 , 54 , 52 , 55 ] ;
102+
103+ // Indicates whether the given string starts with a negative integer.
94104 let mut is_negative = false ;
105+
106+ // Indicates existence of digits in given string.
95107 let mut has_digits = false ;
108+
109+ // Current index position during scanning of input string.
96110 let mut curr_idx: usize = 0 ;
111+
112+ // Indicates whether scanned part should be treated as an integer.
97113 let mut is_started = false ;
114+
115+ // Temp value during looping and return value after looping complete.
98116 let mut val: i32 = 0 ;
117+
118+ // Bytes form of input string. For faster comparison and computation.
99119 let s_bytes = s. as_bytes ( ) ;
120+
121+ // Indicates whether the scanned part correspond to an overflowed interger.
100122 let mut is_overflow = false ;
123+
124+ // In some cases, we should just ignore overflow detection because the
125+ // parsed digits are simply less than same digit in possitive / negative
126+ // overflow threshold value respectively.
127+ let mut is_overflow_ignored = false ;
128+
129+ // Used to check if given string starts with exactly same digits comparing
130+ // with threshold.
101131 let mut is_full_match = true ;
132+
133+ // A vector containing all parsed and valid digits.
102134 let mut val_vec: Vec < u8 > = vec ! [ ] ;
135+
136+ // Loop forever.
137+ // Looping through all characters in sequence or escape during looping are
138+ // controlled by additional flags.
103139 loop {
140+ // Guard condition, exit looping when no more characters to check.
104141 if curr_idx == s_bytes. len ( ) {
105142 break ;
106143 }
107144
108145 if s_bytes[ curr_idx] == 32 {
146+ // This is a whitespace character, check its position.
109147 if !is_started {
110- // Leading whitespace, ignore
148+ // Leading whitespace, ignore it
111149 curr_idx += 1 ;
112150 continue ;
113151 } else {
114- // None leading whitespace, end of reading
152+ // None leading whitespace, end of reading because we already
153+ // found some significant digits.
115154 break ;
116155 }
117156 }
118157
119- if !is_started && [ 43u8 , 45u8 ] . contains ( & s_bytes[ curr_idx] ) {
158+ if [ 43u8 , 45u8 ] . contains ( & s_bytes[ curr_idx] ) {
159+ // Check positive and negative signs.
120160 if has_digits {
121- // Signs after digits (even 0 not allowed)
161+ // Signs after digits (even after 0 is not allowed)
162+ // e.g. `12-222`, `0+123`
122163 break ;
123164 }
124- if s_bytes[ curr_idx] == 45 {
125- is_negative = true ;
126- threshold_val = [ 50 , 49 , 52 , 55 , 52 , 56 , 51 , 54 , 52 , 56 ] ;
165+ if !is_started {
166+ // Should only adjust sign when this is the very first valid
167+ // symbol in the given string.
168+ if s_bytes[ curr_idx] == 45 {
169+ // Adjust flag and set new overflow threshold.
170+ is_negative = true ;
171+ threshold_val = [ 50 , 49 , 52 , 55 , 52 , 56 , 51 , 54 , 52 , 56 ] ;
172+ }
173+ // Setup flag to avoid `-+` sequences.
174+ is_started = true ;
175+ curr_idx += 1 ;
176+ continue ;
127177 }
128- is_started = true ;
129- curr_idx += 1 ;
130- continue ;
131178 }
132179
180+ // Now parse digit and detect overflow.
133181 if 48 <= s_bytes[ curr_idx] && s_bytes[ curr_idx] <= 57 {
182+ // Once a new digit found, update related flags to avoid malformed
183+ // sequences like: `0 123` and `123-6`.
134184 has_digits = true ;
185+ is_started = true ;
186+
135187 if val == 0 && s_bytes[ curr_idx] == 48 {
136188 // Skip leading zeros.
137189 curr_idx += 1 ;
138190 continue ;
139191 }
140192
141193 // Digits
142- for idx in 0 ..val_vec. len ( ) {
194+ if val_vec. len ( ) >= threshold_val. len ( ) - 1 {
195+ // Only check overflow when parsed digits are the same or 1
196+ // digit shorter than threshold. Otherwise it could waste
197+ // execution time.
198+
199+ // The following traversal checks:
200+ // 1. if parsed part has exact same digits as threshold;
201+ // 2. if parsed part should be ignored in future checking.
202+ for idx in 0 ..val_vec. len ( ) {
203+ if !is_overflow {
204+ // Save time
205+ if !is_overflow_ignored && val_vec[ idx] > threshold_val[ idx] {
206+ // One digit is greater than threshold, no need to
207+ // check later ones.
208+ is_overflow = true ;
209+ is_full_match = false ;
210+ break ;
211+ } else if val_vec[ idx] < threshold_val[ idx] {
212+ // One digit is smaller than threshold, means as
213+ // long as its shorter than threshold, it cannot
214+ // overflow.
215+ // But it still needs testing for its length
216+ // in a later step.
217+ is_full_match = false ;
218+ is_overflow_ignored = true ;
219+ }
220+ }
221+ }
222+
143223 if !is_overflow {
144- if val_vec[ idx] > threshold_val[ idx] {
224+ // Test for current digit:
225+ // 1. if it extends length of parsed number that causes
226+ // overflow.
227+ // 2. if it increases parsed number that causes overflow.
228+ if val_vec. len ( ) == threshold_val. len ( ) - 1 {
229+ // Check if adding this digit causes overflow
230+ if is_full_match
231+ && s_bytes[ curr_idx] > threshold_val[ threshold_val. len ( ) - 1 ]
232+ {
233+ is_overflow = true ;
234+ break ;
235+ }
236+ } else if val_vec. len ( ) == threshold_val. len ( ) {
237+ // Check if extending parsed part causes overflow.
145238 is_overflow = true ;
146- is_full_match = false ;
147239 break ;
148- } else if val_vec[ idx] < threshold_val[ idx] {
149- is_full_match = false ;
150240 }
151241 }
152242 }
153- if !is_overflow {
154- // Check if adding this digit causes overflow
155- if is_full_match || val_vec. len ( ) == threshold_val. len ( ) {
156- is_overflow = true ;
157- break ;
158- }
243+ if is_overflow {
244+ // Do NOT prepend current digit to parsed number.
245+ break ;
159246 }
160-
161247 val = val * 10 + ( s_bytes[ curr_idx] - 48 ) as i32 ;
162248 val_vec. push ( s_bytes[ curr_idx] ) ;
163249 curr_idx += 1 ;
@@ -166,6 +252,8 @@ pub fn my_atoi(s: String) -> i32 {
166252
167253 break ;
168254 }
255+ // The following steps simply determines what value to return by
256+ // overflowing flag and integer sign.
169257 if is_overflow {
170258 if is_negative {
171259 -2147483648
0 commit comments