将给定的字符串从上往下、从左到右进行 Z Z Z字形排列为 n u m R o w s numRows numRows行,在按层序读取为一个新的字符串
0123456789 0123456789 0123456789排列成4行为:
0 6 12 1 5 7 11 13 2 4 8 10 14 3 9 15
可以读取为 06121571113... 06121571113... 06121571113...
这是一个找规律题,题目描述为 Z Z Z,但其实是一个倒 N N N。
从上述例子来看,0到5是一个循环,6到11是一个循环。这些循环都是一个等差序列。
并且只有第一行和最后一行是一个等差序列,其余都是两个等差序列交错出现,公差为 2 × n u m R o w s − 2 2\times numRows-2 2×numRows−2。
且第 i i i行的第一个数为 i i i,另一个数为 2 × n u m R o w s − 2 − i 2\times numRows-2-i 2×numRows−2−i。
特判:如果 n u m R o w s = 1 numRows=1 numRows=1,那么只有一行,也就是原字符串。
string convert(string s, int numRows) {
if(numRows == 1) return s; // 特判原字符串
string ans = "";
int p = 2 * numRows - 2, n = s.length();
for(int i = 0; i < numRows; i ++) { // 第i行
if(i == 0 || i == numRows - 1) {
for(int j = i; j < n; j += p)
ans += s[j];
}else {
for(int j = i, k = p - i; j < n || k < n; j += p, k += p) {
if(j < n) ans += s[j];
if(k < n) ans += s[k];
}
}
}
return ans;
}
给定32位有符号整数,返回翻转后的整数。若爆
int
则返回0,且不允许使用long long
。
要将1234
翻转成4321
,可以将个位数4
提取出来,然后将原数除10
得到123
。循环这个过程,并将答案的4
乘10
再加得到的个位数。
即ans = ans * 10 + x % 10
。这对于正数显然成立。
对于负数,由于在c++中-4 % 4 = -4
,-4 * 10 + -5 = -45
,所以以上规则也成立。
可以这样判断得到的答案是否会爆int
:
I N T _ M I N ≤ 10 a n s + x % 10 ≤ I N T _ M A X I N T _ M I N − x % 10 10 ≤ a n s ≤ I N T _ M A X − x % 10 10 INT\_MIN\leq10ans+x\%10 \leq INT\_MAX \\ \frac{INT\_MIN-x\%10}{10} \leq ans \leq \frac{INT\_MAX-x\%10}{10} INT_MIN≤10ans+x%10≤INT_MAX10INT_MIN−x%10≤ans≤10INT_MAX−x%10
上式必须化简,否则会爆int
。
当 x x x为正数时,始终只要判断是否超过上限。 x x x为负数时,始终只要判断是否超过下限即可。
int reverse(int x) {
int ans = 0;
while(x) {
if (x > 0 && ans > (INT_MAX - x % 10) / 10) return 0;
if (x < 0 && ans < (INT_MIN - x % 10) / 10) return 0;
ans = ans * 10 + x % 10;
x /= 10;
}
return ans;
}
实现一个能将字符串转换为整数的函数。步骤如下:
- 去除前导空格;
- 检查正负号,如果没有默认为正数;
- 读入数字字符,直到到达末尾或到达非数字字符,并转换为整数;
- 若未读入数字,则答案为0,若超过32位整数范围,小于 − 2 31 -2^{31} −231固定为 − 2 31 -2^{31} −231,大于 2 31 − 1 2^{31}-1 231−1固定为 2 31 − 1 2^{31}-1 231−1。
和上一题类似,但是这题需要特判-2147483648
的情况。
因为前面判断完正负号之后,后面的数值若为2147483648
会超过int
能表示的最大整数。
− 10 × a n s − p ≥ I N T _ M I N -10\times ans-p \geq INT\_MIN\\ −10×ans−p≥INT_MIN
但是对于 − 10 × a n s − p = I N T _ M I N = − 2147483648 -10\times ans-p=INT\_MIN = -2147483648 −10×ans−p=INT_MIN=−2147483648是正确的,但是 10 × a n s + p = I N T _ M A X = 2147483648 10 \times ans+p=INT\_MAX=2147483648 10×ans+p=INT_MAX=2147483648会爆int
。
所以需要特判这个情况,成为 − 10 × a n s − p = I N T _ M I N -10 \times ans -p = INT\_MIN −10×ans−p=INT_MIN,但是这个式子不能化简,因为 / 10 /10 /10会过滤2147483647
等情况。
int myAtoi(string s) {
int k = 0, flag = 1, ans = 0;
while(s[k] == ' ') k ++; // 去除前导空格
if(s[k] == '-') flag = -1, k ++;
else if(s[k] == '+') k ++;
while(s[k] >= '0' && s[k] <= '9') {
int p = s[k] - '0';
if(flag == 1 && ans > (INT_MAX - p) / 10) return INT_MAX;
// [-2147483648, 2147483647] 负数需要特判-2147483648的情况
if(flag == -1 && -ans < (INT_MIN + p) / 10) return INT_MIN;
if(-10 * ans - p == INT_MIN) return INT_MIN;
ans = ans * 10 + p;
k ++;
}
return ans * flag;
}
给定整数,判断是否为回文整数。
可以将整数转换为字符串,然后判断是否为回文串。
bool isPalindrome(int x) {
string str = to_string(x), ss = to_string(x);
reverse(ss.begin(), ss.end());
return str == ss;
}
给定两个字符串,问能否匹配,匹配规则如下:
.
匹配任意单个字符*
匹配零个或多个前面的那一个元素
令 f ( i , j ) f(i,j) f(i,j)表示 S [ 1.. i ] S[1..i] S[1..i]和 P [ 1.. j ] P[1..j] P[1..j]是否匹配。显然, f ( i , 0 ) f(i,0) f(i,0)不可能匹配( f ( 0 , 0 ) f(0,0) f(0,0)除外)。
在不考虑通配符的情况下,f(i,j)=f(i-1,j-1) && (S[i] = P[j])
。
考虑.
通配符时,f(i,j)=f(i-1,j-1) && (P[j] == '.')
考虑*
通配符时,若j >= 2
,那么f(i, j) = f(i, j - 2)
表示匹配零次前面的元素。
如果匹配一次前面的元素,那么f(i, j) = f(i - 1, j - 2) && (s[i] == p[j - 1] || p[j - 1] == '.')
。
如果匹配两次前面的元素,那么f(i, j) = f(i - 2, j - 2) && ...
。
也就是说f(i, j) = f(i, j - 2) + f(i - 1, j - 2) + f(i - 2, j - 2) + ...
。
类似完全背包的转移方式,又有f(i - 1, j) = f(i - 1, j - 2) + f(i - 2, j - 2) + f(i - 3, j - 2) + ...
。
所以f(i, j) = f(i - 1, j) + f(i, j - 2)
。
要使得S[i-1]
和P[j]
能匹配,那么需要s[i]
和p[j - 1]
能成功匹配,也就是说S
的最后一个元素要能和P
的*
之前的元素能匹配。
bool isMatch(string s, string p) {
int m = s.length(), n = p.length();
s = " " + s, p = " " + p;
vector<vector<bool>> f(m + 10, vector<bool>(n + 10));
f[0][0] = true;
for(int i = 0; i <= m; i ++) { // s[0..0]是可以和'a*'匹配的,所以从0开始
for(int j = 1; j <= n; j ++) { // 若P="",那么无法匹配,所以下标从1开始
if(j + 1 <= n && p[j] != '*' && p[j + 1] == '*') continue; // a*需要结合起来使用
// 这里有一个特殊样例
// s = "abc"
// p = "a***abc"
// 显然p[0][2] = true,因为a*可以匹配0次
// 所以多个*视作一个*
if(i > 0 && p[j] != '*')
f[i][j] = f[i - 1][j - 1] && (p[j] == '.' || p[j] == s[i]);
else if(p[j] == '*') // i必须要先大于0才能判断i-1
f[i][j] = f[i][j - 2] || (i > 0 && f[i - 1][j]
&& (p[j - 1] == '.' || p[j - 1] == s[i]));
}
}
return f[m][n];
}