rustgym/leetcode/
_65_valid_number.rs1struct Solution;
2
3use std::cmp::Ordering::*;
4use std::iter::Peekable;
5use std::vec::IntoIter;
6
7#[derive(PartialEq, Eq, Clone, Copy)]
8enum Tok {
9 Num(i32),
10 Op(char),
11}
12
13impl Solution {
14 fn is_number(s: String) -> bool {
15 let s = s.trim();
16 let mut it = s.chars().peekable();
17 let mut tokens: Vec<Tok> = vec![];
18 let mut e_count = 0;
19 while let Some(c) = it.next() {
20 match c {
21 ' ' | '-' | '+' | '.' => {
22 tokens.push(Tok::Op(c));
23 }
24 'e' => {
25 e_count += 1;
26 if e_count == 2 {
27 return false;
28 }
29 tokens.push(Tok::Op(c));
30 }
31 '0'..='9' => {
32 let mut x = (c as u8 - b'0') as i32;
33 while let Some('0'..='9') = it.peek() {
34 x *= 10;
35 x += (it.next().unwrap() as u8 - b'0') as i32;
36 }
37 tokens.push(Tok::Num(x));
38 }
39 _ => {
40 return false;
41 }
42 }
43 }
44
45 if let Some(e_pos) = tokens.iter().position(|&x| x == Tok::Op('e')) {
46 let mut left = vec![];
47 let mut right = vec![];
48 for (i, tok) in tokens.into_iter().enumerate() {
49 match i.cmp(&e_pos) {
50 Less => {
51 left.push(tok);
52 }
53 Greater => {
54 right.push(tok);
55 }
56 _ => {}
57 }
58 }
59 Self::parse_float(&mut left.into_iter().peekable())
60 && Self::parse_int(&mut right.into_iter().peekable())
61 } else {
62 Self::parse_float(&mut tokens.into_iter().peekable())
63 }
64 }
65
66 fn parse_int(it: &mut Peekable<IntoIter<Tok>>) -> bool {
67 if let Some(Tok::Op('+')) | Some(Tok::Op('-')) = it.peek() {
68 it.next();
69 }
70 Self::parse_uint(it)
71 }
72
73 fn parse_uint(it: &mut Peekable<IntoIter<Tok>>) -> bool {
74 if let Some(Tok::Num(_)) = it.next() {
75 it.next().is_none()
76 } else {
77 false
78 }
79 }
80
81 fn parse_ufloat(it: &mut Peekable<IntoIter<Tok>>) -> bool {
82 match it.peek() {
83 Some(Tok::Op('.')) => {
84 it.next();
85 Self::parse_uint(it)
86 }
87 Some(Tok::Num(_)) => {
88 it.next();
89 match it.peek() {
90 Some(Tok::Op('.')) => {
91 it.next();
92 if it.peek().is_none() {
93 true
94 } else {
95 Self::parse_uint(it)
96 }
97 }
98 None => true,
99 _ => false,
100 }
101 }
102 _ => false,
103 }
104 }
105
106 fn parse_float(it: &mut Peekable<IntoIter<Tok>>) -> bool {
107 if let Some(Tok::Op('+')) | Some(Tok::Op('-')) = it.peek() {
108 it.next();
109 }
110
111 Self::parse_ufloat(it)
112 }
113}
114
115#[test]
116fn test() {
117 let s = "0".to_string();
118 let res = true;
119 assert_eq!(Solution::is_number(s), res);
120 let s = " 0.1 ".to_string();
121 let res = true;
122 assert_eq!(Solution::is_number(s), res);
123 let s = "abc".to_string();
124 let res = false;
125 assert_eq!(Solution::is_number(s), res);
126 let s = "1 a".to_string();
127 let res = false;
128 assert_eq!(Solution::is_number(s), res);
129 let s = "2e10".to_string();
130 let res = true;
131 assert_eq!(Solution::is_number(s), res);
132 let s = " -90e3".to_string();
133 let res = true;
134 assert_eq!(Solution::is_number(s), res);
135 let s = " 1e".to_string();
136 let res = false;
137 assert_eq!(Solution::is_number(s), res);
138 let s = "e3".to_string();
139 let res = false;
140 assert_eq!(Solution::is_number(s), res);
141 let s = " 6e-1".to_string();
142 let res = true;
143 assert_eq!(Solution::is_number(s), res);
144 let s = " 99e2.5".to_string();
145 let res = false;
146 assert_eq!(Solution::is_number(s), res);
147 let s = " 53.5e93".to_string();
148 let res = true;
149 assert_eq!(Solution::is_number(s), res);
150 let s = " --6 ".to_string();
151 let res = false;
152 assert_eq!(Solution::is_number(s), res);
153 let s = "-+3".to_string();
154 let res = false;
155 assert_eq!(Solution::is_number(s), res);
156 let s = "95a54e53".to_string();
157 let res = false;
158 assert_eq!(Solution::is_number(s), res);
159 let s = ".1".to_string();
160 let res = true;
161 assert_eq!(Solution::is_number(s), res);
162 let s = "3.".to_string();
163 let res = true;
164 assert_eq!(Solution::is_number(s), res);
165 let s = ". 1".to_string();
166 let res = false;
167 assert_eq!(Solution::is_number(s), res);
168}