L3 无重复字符的最长子串
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> us;
int left = 0, right = 0;
int out = 0;
while (right < s.size()) {
us.emplace(s[right++]);
out = max(out, right - left);
while (!us.empty() && us.count(s[right]))
us.erase(s[left++]);
}
return out;
}
};
L5 最长回文子串
- 子串:连续的
- 回文
- dp[i][j]表示i~j是不是回文
- 遍历次序先从字长1~N遍历!
class Solution {
public:
string longestPalindrome(string s) {
int N = s.size();
if (N < 2) return s;
vector<vector<bool>> dp(N, vector<bool>(N, false));
int start = 0, len = 0;
for (int i = 1; i <= N; i++) {
for (int j = 0; j <= N - i; j++) {
int p = j + i - 1;
dp[j][p] = (s[j] == s[p]) && (p - j < 2 || dp[j+1][p-1]);
if (dp[j][p] && i > len) {
start = j; len = i;
}
}
}
return s.substr(start, len);
}
};
L6 Z字形变换

class Solution {
public:
string convert(string s, int numRows) {
int N = 2 * numRows - 2;
int LEN = s.size();
if (LEN <= numRows || numRows == 1) return s;
int i = 0;
string out[numRows];
for (i = 0; i < LEN; i += N) {
int j = i + N - 1;
for (int k = i; k <= min(j, LEN-1); k++) {
if (k <= i + numRows - 1) {
out[k-i].push_back(s[k]);
} else {
out[N - k + i].push_back(s[k]);
}
}
}
string res;
for (int i = 0; i < numRows; i++)
res += out[i];
return res;
}
};
class Solution {
public:
string convert(string s, int numRows) {
int n = s.size();
if (n < 1 || numRows == 1) return s;
string out[min(n, numRows)];
bool dir = false;
int idx = 0;
for (auto& c : s) {
out[idx] += c;
if (idx == 0 || idx == numRows - 1)
dir = !dir;
idx += dir ? 1 : -1;
}
string res = "";
for (auto& ss : out)
res += ss;
return res;
}
};
L8 字符串转换整数 (atoi)
- 一串字符串转换为整数
- 如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
- 假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
- 该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
“臃肿的代码”
class Solution {
public:
int myAtoi(string str) {
if (str.empty()) return 0;
int idx = 0, idx2 = 0;
for (idx = 0; idx < str.size(); idx++) {
if (str[idx] != ' ') break;
}
if (idx == str.size()) return 0;
int sgn = (str[idx] == '-') ? -1 :
(isdigit(str[idx]) || str[idx] == '+') ? 1 : -2;
if (sgn == -2) return 0;
for (idx2 = idx + 1; idx2 < str.size(); idx2++) {
if (!isdigit(str[idx2]))
break;
}
string num = str.substr(idx, idx2 - idx);
long long x = 0;
int idx3 = idx;
for (idx3 = idx; idx3 < idx2; idx3++)
if (isdigit(str[idx3])) break;
for (int i = idx3; i < idx2; i++) {
if (sgn * x * 10 > INT_MAX) return INT_MAX;
else if ( sgn *x * 10 < INT_MIN) return INT_MIN;
x = x * 10 + str[i] - '0';
}
x *= sgn;
if (x > INT_MAX) return INT_MAX;
else if ( x < INT_MIN) return INT_MIN;
else return x;
}
};
确定有限状态机
(deterministic finite automaton, DFA)

X |
’ ’ 0 |
+/- 1 |
number 2 |
other 3 |
start 0 |
start |
signed |
in_number |
end |
signed 1 |
end |
end |
in_number |
end |
in_number 2 |
end |
end |
in_number |
end |
end 3 |
end |
end |
end |
end |
class Solution {
private:
class DFA {
private:
int state_move[4][4] {{0,1,2,3},{3,3,2,3},
{3,3,2,3},{3,3,3,3}};
int sgn = 1;
long long num = 0;
int state = 0;
public:
int get_move(char c) {
if (isspace(c)) return 0;
else if (c == '+' || c == '-') return 1;
else if (isdigit(c)) return 2;
else return 3;
}
void run(char c) {
state = state_move[state][get_move(c)];
if (state == 1) sgn = (c == '-') ? -1 : 1;
else if (state == 2) {
num = num * 10 + c - '0';
if (sgn == 1) num = min(num, (long long)INT_MAX);
else num = min(num, -1 * (long long)INT_MIN);
}
}
int get_num() {
return num * sgn;
}
};
public:
int myAtoi(string str) {
DFA d;
for (auto& c : str) d.run(c);
return d.get_num();
}
};
L12 整数转罗马数字
- 输入一个整数,转换为罗马表示形式
- 贪心 + 列表 从大数表示
class Solution {
private:
string L[13] {"I", "IV", "V", "IX", "X", "XL", "L",
"XC", "C", "CD", "D", "CM", "M"};
int N[13] {1, 4, 5, 9, 10, 40, 50,
90, 100, 400, 500, 900, 1000};
public:
string intToRoman(int num) {
if (num == 0) return "N";
string out = "";
for (int i = 12; i >= 0; i--) {
int a = num / N[i];
if (a == 0) continue;
for (int j = 0; j < a; j++)
out += L[i];
num = num % N[i];
}
return out;
}
};
L13 罗马数字转整数
class Solution {
private:
unordered_map<string, int> R {{"M", 1000}, {"CM", 900},
{"D", 500}, {"CD", 400}, {"C", 100}, {"XC", 90}, {"L", 50},
{"XL", 40}, {"X", 10}, {"IX", 9}, {"V", 5}, {"IV", 4}, {"I", 1}};
public:
int romanToInt(string s) {
if (s.empty()) return 0;
if (s.size() == 1) {
if (R.count(s) == 0) return 0;
else return R[s];
}
int res = 0;
s.push_back('N');
for (int i = 0; i < s.size() - 1;) {
string a = s.substr(i, 1);
string b = s.substr(i, 2);
int na = 0, nb = 0;
if (R.count(a)) na = R[a];
if (R.count(b)) nb = R[b];
if (na == 0 && nb == 0) return 0;
if (nb > na) {res += nb; i+=2;}
else {res += na; i++;}
}
return res;
}
};
class Solution {
private:
unordered_map<char, int> L {{'I', 1},
{'V', 5}, {'X', 10}, {'L', 50},
{'C', 100}, {'D', 500}, {'M', 1000}};
int getNum(char x) {
switch (x) {
case 'I' : return 1;
case 'V' : return 5;
case 'X' : return 10;
case 'L' : return 50;
case 'C' : return 100;
case 'D' : return 500;
case 'M' : return 1000;
default : return 0;
}
}
public:
int romanToInt(string s) {
int out = 0;
for (int i = 0; i < s.size() - 1; i++) {
int n1 = getNum(s[i]), n2 = getNum(s[i + 1]);
if (n1 == 0 && n2 == 0) return 0;
if (n1 < n2) out -= n1;
else out += n1;
}
out += getNum(s.back());
return out;
}
};
L14 最长公共前缀
- 编写一个函数来查找字符串数组中的最长公共前缀。
- 如果不存在公共前缀,返回空字符串 “”
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if(strs.empty()) return "";
const auto p = minmax_element(strs.begin(), strs.end());
for(int i = 0; i < p.first->size(); ++i)
if(p.first->at(i) != p.second->at(i)) return p.first->substr(0, i);
return *p.first;
}
};
L38 外观数列
- 「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:
1. |
1 |
2. |
11 |
3. |
21 |
4. |
1211 |
5. |
111221 |
class Solution {
public:
string countAndSay(int n) {
if (n < 2) return to_string(n);
string out = "1";
while (n > 1) {
int cnt = 1;
string str = "";
for (int i = 0; i < out.size(); i++) {
char x = out[i];
if (i + 1 < out.size() && out[i + 1] == out[i])
cnt++;
else {
str += to_string(cnt);
str.push_back(x);
cnt = 1;
}
}
n--;
out = str;
}
return out;
}
};
L30 串联所有单词的子串
- 字符串 s 和 长度相同的单词集合words
- 从s中找到可以由集合组合成的字符子串 的起始位置
暴力搜素
,用哈希表记录每个word的个数
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if (s.empty() || words.empty()) return {};
int N1 = s.size(), N2 = words.size(), N3 = words[0].size();
if (N1 < N2 * N3) return {};
vector<int> out;
unordered_map<string, int> m1, m2;
string buff;
for (auto& w : words) m1[w]++;
for (int i = 0; i < N1; i++) {
if (N1 - i + 1 < N2 * N3) break;
m2 = m1;
buff = s.substr(i, N3);
int j = i, count = 0;
while (m2[buff] > 0) {
m2[buff]--;
count++;
j += N3;
buff = s.substr(j, N3);
}
if (count == N2)
out.push_back(i);
}
return out;
}
};
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if (words.size() == 0) return {};
unordered_map<string, int> m;
for (auto& w : words) m[w]++;
int word_len = words[0].size();
vector<int> out;
for (int i = 0; i < word_len; i++) {
int left = i, right = i;
int cnt = 0;
unordered_map<string, int> win;
while (left + words.size() * word_len <= s.size()) {
string tmp = "";
while (cnt < words.size()) {
tmp = s.substr(right, word_len);
if (m.count(tmp) == 0 || win[tmp] >= m[tmp])
break;
win[tmp]++;
cnt++;
right += word_len;
}
if (win == m) out.push_back(left);
if (m.count(tmp)) {
win[s.substr(left, word_len)]--;
left += word_len;
cnt--;
} else {
right += word_len;
left = right;
cnt = 0;
win.clear();
}
}
}
return out;
}
};
L43 字符串相乘
- 字符串表示的两个非负整数,返回其乘积
- 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
- i+j的位置就是输出字符串的基本位置(存在进位)
class Solution {
public:
string multiply(string num1, string num2) {
int sz1 = num1.size();
int sz2 = num2.size();
if (sz1 == 0) return num2;
if (sz2 == 0) return num1;
string res = "";
res.resize(sz1 + sz2, '0');
for (int i = 1; i <= sz1; i++) {
for (int j = 1; j <= sz2; j++) {
int a = num1[i-1] - '0';
int b = num2[j-1] - '0';
int c = res[i+j-1] - '0';
int tmp = a * b + c;
res[i+j-1] = tmp % 10 + '0';
res[i+j-2] += tmp / 10;
}
}
for (int i = res.size() - 1; i > 0; i--) {
int tmp = res[i] - '0';
res[i] = tmp % 10 + '0';
res[i-1] += tmp / 10;
}
int start = 0;
for (int i = 0; i < res.size(); i++) {
if (res[i] != '0') return res.substr(i);
}
return "0";
}
};
- 上面的第二步可以不需要,如果第一步是从低位累积起来的
class Solution {
public:
string multiply(string num1, string num2) {
int sz1 = num1.size();
int sz2 = num2.size();
if (sz1 == 0) return num2;
if (sz2 == 0) return num1;
string res = "";
res.resize(sz1 + sz2, '0');
for (int i = sz1; i >= 1; i--) {
for (int j = sz2; j >= 1; j--) {
int a = num1[i-1] - '0';
int b = num2[j-1] - '0';
int c = res[i+j-1] - '0';
int tmp = a * b + c;
res[i+j-1] = tmp % 10 + '0';
res[i+j-2] += tmp / 10;
}
}
int start = 0;
for (int i = 0; i < res.size(); i++) {
if (res[i] != '0') return res.substr(i);
}
return "0";
}
};
L65 有效数字
- 输入一串字符串,判断能不能转换为数字

- 只考虑有效的状态之间的转移,这样画图会简单一点
- 直接失效的直接设为-1,不用进行转移过程了!
class DFA {
private:
int state_move[9][6] {
{0,1,2,-1,6,-1},
{-1,-1,2,-1,6,-1},
{-1,-1,-1,-1,3,-1},
{8,-1,-1,4,3,-1},
{-1,7,-1,-1,5,-1},
{8,-1,-1,-1,5,-1},
{8,-1,3,4,6,-1},
{-1,-1,-1,-1,5,-1},
{8,-1,-1,-1,-1,-1}};
int valid_state[4] {3,5,6,8};
int state = 0;
public:
int get_move(char c) {
if (isspace(c)) return 0;
else if (c == '+' || c == '-') return 1;
else if (c == '.') return 2;
else if (c == 'e') return 3;
else if (isdigit(c)) return 4;
else return 5;
}
void run(char c) {
if (state >= 0)
state = state_move[state][get_move(c)];
}
int get_state() {
return state;
}
bool isValid() {
for (auto& s : valid_state)
if (state == s) return true;
return false;
}
};
class Solution {
public:
bool isNumber(string s) {
DFA d;
for (auto& c : s)
d.run(c);
return d.isValid();
}
};
L93 复原IP地址
输入: “25525511135”
输出: [“255.255.11.135”, “255.255.111.35”]
class Solution {
vector<string> res;
vector<int> segs;
int LEN = 4;
public:
vector<string> restoreIpAddresses(string s) {
segs.resize(LEN, 0);
dfs(s, 0, 0);
return res;
}
void dfs(string& s, int idx, int pos) {
if (idx == LEN && pos == s.size()) {
string tmp = "";
for (int i = 0; i < LEN; i++) {
tmp += to_string(segs[i]);
tmp += ".";
}
tmp.pop_back();
res.push_back(tmp);
return;
}
if (idx == LEN || pos == s.size()) return;
if (s[pos] == '0') {
segs[idx] = 0;
dfs(s, idx+1, pos+1);
}
int num = 0;
for (int i = pos; i < s.size(); i++) {
num = num * 10 + (s[i] - '0');
if (num > 0 && num <= 255) {
segs[idx] = num;
dfs(s, idx + 1, i + 1);
} else break;
}
}
};
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
int n = s.size();
if (n > 12) return {};
for (int i = 0; i < min(3, n - 3); i++) {
for (int j = i + 1; j < min(j + 3, n - 2); j++) {
for (int k = j + 1; k < min(k + 3, n - 1); k++) {
if (n - k > 4) continue;
string s1 = s.substr(0, i + 1);
if (s1[0] == '0' && s1 != "0") continue;
string s2 = s.substr(i + 1, j - i);
if (s2[0] == '0' && s2 != "0") continue;
string s3 = s.substr(j + 1, k - j);
if (s3[0] == '0' && s3 != "0") continue;
string s4 = s.substr(k + 1);
if (s4[0] == '0' && s4 != "0") continue;
long n1 = stol(s1), n2 = stol(s2);
long n3 = stol(s3), n4 = stol(s4);
if (n1 >= 0 && n1 <= 255 && n2 >= 0 && n2 <= 255
&& n3 >= 0 && n3 <= 255 && n4 >= 0 && n4 <= 255) {
string tmp = s1 + "." + s2 + "." + s3 + "." + s4;
res.push_back(tmp);
}
}
}
}
return res;
}
};