CONTENTS
- LeetCode 6. N 字形变换(中等)
- LeetCode 7. 整数反转(中等)
- LeetCode 8. 字符串转换整数-atoi(中等)
LeetCode 6. N 字形变换(中等)
【题目描述】
将一个给定字符串 s
根据给定的行数 numRows
,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING"
行数为 3
时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"
。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
【示例1】
输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"
【示例2】
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
【示例3】
输入:s = "A", numRows = 1
输出:"A"
【提示】
1
≤
s
.
l
e
n
g
t
h
≤
1000
1\le s.length\le 1000
1≤s.length≤1000
1
≤
n
u
m
R
o
w
s
≤
1000
1\le numRows\le 1000
1≤numRows≤1000
s
由英文字母(小写和大写)、','
和 '.'
组成
【分析】
如上图所示,我们用数字来观察规律,设行数为 n n n。
首先看第一行,0到6一共间隔 2 n − 2 2n-2 2n−2 个数,因为从0走到3有 n − 1 n-1 n−1 个数,3走到6也有 n − 1 n-1 n−1 个数,因此第一行为从0开始的公差为 2 n − 2 2n-2 2n−2 的等差数列。同理最后一行为从 n − 1 n-1 n−1 开始的公差为 2 n − 2 2n-2 2n−2 的等差数列。
对于中间行,以第二行为例,由两个等差数列组成,一个是在直线上的数列:1、7、13,这是从1开始的公差为 2 n − 2 2n-2 2n−2 的等差数列;还有一个是在斜线上的数列:5、11、17,这是从5(可以看成 2 n − 2 − i 2n-2-i 2n−2−i, i i i 表示这一行的第一个数)开始的公差为 2 n − 2 2n-2 2n−2 的等差数列。因此中间行就是先输出第一个等差数列的第一项,然后输出第二个等差数列的第一项,再输出第一个等差数列的第二项,以此类推。
【代码】
class Solution {
public:
string convert(string s, int n) {
if (n == 1) return s; // 特判
string res;
for (int i = 0; i < n; i++)
{
if (i == 0 || i == n - 1) // 第一行或最后一行
for (int j = i; j < s.size(); j += 2 * n - 2)
res += s[j];
else
// j表示第一个等差数列,k表示第二个等差数列
for (int j = i, k = 2 * n - 2 - i; j < s.size() || k < s.size(); j += 2 * n - 2, k += 2 * n - 2)
{
if (j < s.size()) res += s[j];
if (k < s.size()) res += s[k];
}
}
return res;
}
};
LeetCode 7. 整数反转(中等)
【题目描述】
给你一个 32 位的有符号整数 x
,返回将 x
中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围
[
−
2
31
,
2
31
−
1
]
[-2^{31}, 2^{31} - 1]
[−231,231−1],就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
【示例1】
输入:x = 123
输出:321
【示例2】
输入:x = -123
输出:-321
【示例3】
输入:x = 120
输出:21
【示例4】
输入:x = 0
输出:0
【提示】
− 2 31 ≤ x ≤ 2 31 − 1 -2^{31}\le x\le 2^{31} - 1 −231≤x≤231−1
【分析】
首先有个小 Tips:C++中负数取模的结果也为负数,如 − 1234 % 10 = − 4 -1234\% 10=-4 −1234%10=−4。
直接用 x % 10 x\% 10 x%10 求出 x x x 的个位数 a a a,然后 r e s = r e s ∗ 10 + a res=res*10+a res=res∗10+a,根据负数取模的特性易知该方式同样适用于负数。
注意我们当做无法使用 long long
类型,因此做溢出判断的时候需要对判断公式做一个变换。
【代码】
class Solution {
public:
int reverse(int x) {
int res = 0;
while (x)
{
// res * 10 + x % 10 > MAX -> res > (MAX - x % 10) / 10
if (res > 0 && res > (INT_MAX - x % 10) / 10) return 0;
if (res < 0 && res < (INT_MIN - x % 10) / 10) return 0;
res = res * 10 + x % 10; // x不管正负都通用
x /= 10;
}
return res;
}
};
LeetCode 8. 字符串转换整数-atoi(中等)
【题目描述】
请你来实现一个 myAtoi(string s)
函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi
函数)。
函数 myAtoi(string s)
的算法如下:
- 读入字符串并丢弃无用的前导空格。
- 检查下一个字符(假设还未到字符串末尾)为正还是负号,读取该字符(如果有)。确定最终结果是负数还是正数。如果两者都不存在,则假定结果为正。
- 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
- 将前面步骤读入的这些数字转换为整数(即,“123” -> 123,“0032” -> 32)。如果没有读入数字,则整数为 0。必要时更改符号(从步骤 2 开始)。
- 如果整数数超过 32 位有符号整数范围 [ − 2 31 , 2 31 − 1 ] [-2^{31}, 2^{31} - 1] [−231,231−1],需要截断这个整数,使其保持在这个范围内。具体来说,小于 − 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。
- 返回整数作为最终结果。
注意:
- 本题中的空白字符只包括空格字符
' '
。 - 除前导空格或数字后的其余字符串外,请勿忽略任何其他字符。
【示例1】
输入:s = "42"
输出:42
【示例2】
输入:s = " -42"
输出:-42
【示例3】
输入:s = "4193 with words"
输出:4193
【提示】
0
≤
s
.
l
e
n
g
t
h
≤
200
0\le s.length\le 200
0≤s.length≤200
s
由英文字母(大写和小写)、数字(0-9)、' '
、'+'
、'-'
和 '.'
组成
【分析】
模拟处理字符串即可,判断溢出的方式与上一题相似,唯一的一个坑点是负数的最小值的绝对值是比正数的最大值多1的,因此当恰好等于最小值时 r e s res res 存不下对应的正数,因此需要直接返回最小值。
【代码】
class Solution {
public:
int myAtoi(string s) {
int idx = 0;
while (idx < s.size() && s[idx] == ' ') idx++; // 过滤前导空格
int op = 1; // 标记正负,没有正负号时默认为正
if (s[idx] == '-') op *= -1, idx++;
else if (s[idx] == '+') idx++;
int res = 0;
while (idx < s.size() && s[idx] >= '0' && s[idx] <= '9')
{
int x = s[idx] - '0';
// res * 10 + x > MAX -> res > (MAX - x) / 10
if (op > 0 && res > (INT_MAX - x) / 10) return INT_MAX;
// -res * 10 - x < MIN -> -res < (MIN + x) / 10
if (op < 0 && -res < (INT_MIN + x) / 10) return INT_MIN;
if (-res * 10 - x == INT_MIN) return INT_MIN; // 特判刚好等于最小值
res = res * 10 + x;
idx++;
}
return res * op;
}
};