1. 回文数

image-20200628161222446
我的思路:

直接将整数转化为字符串,使用字符串相关的函数将字符串反转后与原串作比较

代码实现:
1
2
3
4
5
6
class Solution {
public boolean isPalindrome(int x) {
return new StringBuilder(String.valueOf(x)).toString()
.equals(new StringBuilder(String.valueOf(x)).reverse().toString());
}
}
执行结果:
image-20200628163110346

可以看出执行效率较差、占用空间也较多!

更好的方法:

映入脑海的第一个想法是将数字转换为字符串,并检查字符串是否为回文。但是,这需要额外的非常量空间来创建问题描述中所不允许的字符串。

第二个想法是将数字本身反转,然后将反转后的数字与原始数字进行比较,如果它们是相同的,那么这个数字就是回文。
但是,如果反转后的数字大于 \text{int.MAX}int.MAX,我们将遇到整数溢出问题。

按照第二个想法,为了避免数字反转可能导致的溢出问题,为什么不考虑只反转 \text{int}int 数字的一半?毕竟,如果该数字是回文,其后半部分反转后应该与原始数字的前半部分相同。

例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。

fig1

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/palindrome-number/solution/hui-wen-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public boolean isPalindrome(int x) {
// 特殊情况:
// 如上所述,当 x < 0 时,x 不是回文数。
// 同样地,如果数字的最后一位是 0,为了使该数字为回文,
// 则其第一位数字也应该是 0
// 只有 0 满足这一属性
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}

int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}

// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
}

2. 罗马数字转整数

image-20200628171957342
我的思路:

使用 HashMap 将罗马数字与对应的值作为键值对存储,然后分类讨论各种情况!

代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Solution {
public int romanToInt(String s) {
int res = 0;
HashMap<Character, Integer> map = new HashMap<>();
map.put('I', 1);
map.put('V', 5);
map.put('X', 10);
map.put('L', 50);
map.put('C', 100);
map.put('D', 500);
map.put('M', 1000);

for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == 'I') { // I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
if (i + 1 < s.length() && s.charAt(i + 1) == 'V') {
res += map.get('V') - map.get('I');
i++;
} else if (i + 1 < s.length() && s.charAt(i + 1) == 'X') {
res += map.get('X') - map.get('I');
i++;
} else {
res += map.get('I');
}
} else if (s.charAt(i) == 'V') {
res += map.get('V');
} else if (s.charAt(i) == 'X') { // X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
if (i + 1 < s.length() && s.charAt(i + 1) == 'L') {
res += map.get('L') - map.get('X');
i++;
} else if (i + 1 < s.length() && s.charAt(i + 1) == 'C') {
res += map.get('C') - map.get('X');
i++;
} else {
res += map.get('X');
}
} else if (s.charAt(i) == 'L') {
res += map.get('L');
} else if (s.charAt(i) == 'C') { // C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
if (i + 1 < s.length() && s.charAt(i + 1) == 'D') {
res += map.get('D') - map.get('C');
i++;
} else if (i + 1 < s.length() && s.charAt(i + 1) == 'M') {
res += map.get('M') - map.get('C');
i++;
} else {
res += map.get('C');
}
} else if (s.charAt(i) == 'D') {
res += map.get('D');
} else {
res += map.get('M');
}
}

return res;
}
}
执行结果:
image-20200628172259917

代码较为繁琐且执行效率并不高!

更好的方法:

把一个小值放在大值的左边,就是做减法,否则为加法

![Screen Shot 2020-02-17 at 21.14.47.png](【数据结构与算法】LeetCode:day5/9d092fd44be4a809487a326dd6e9adcdddb1b27b6f5ec02ce60651745ff43528-Screen Shot 2020-02-17 at 21.14.47.png)

在代码实现上,可以往后看多一位,对比当前位与后一位的大小关系,从而确定当前位是加还是减法。当没有下一位时,做加法即可。

也可保留当前位的值,当遍历到下一位的时,对比保留值与遍历位的大小关系,再确定保留值为加还是减。最后一位做加法即可。

作者:donespeak
链接:https://leetcode-cn.com/problems/roman-to-integer/solution/yong-shi-9993nei-cun-9873jian-dan-jie-fa-by-donesp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.*;

class Solution {
public int romanToInt(String s) {
int sum = 0;
int preNum = getValue(s.charAt(0));
for(int i = 1;i < s.length(); i ++) {
int num = getValue(s.charAt(i));
if(preNum < num) {
sum -= preNum;
} else {
sum += preNum;
}
preNum = num;
}
sum += preNum;
return sum;
}

// 使用 switch 替换 HashMap,极大提升了效率(小数据量时)
private int getValue(char ch) {
switch(ch) {
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;
}
}
}

/*
作者:donespeak
链接:https://leetcode-cn.com/problems/roman-to-integer/solution/yong-shi-9993nei-cun-9873jian-dan-jie-fa-by-donesp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/

3. 最长公共前缀

image-20200628180537264
我的思路:

暴力匹配法,直接嵌套循环从前往后判断各字符串中的第n个字母是否相同,相同则加入到 StringBuilder 中

代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs.length == 0) return "";
StringBuilder sb = new StringBuilder("");
int length = strs[0].length();
boolean flag = true;
for (int i = 1; i < strs.length; i++) {
if (strs[i].length() < length) {
length = strs[i].length();
}
}

for (int i = 0; i < length; i++) {
for (int j = 1; j < strs.length; j++) {
if (strs[j].charAt(i) != strs[j - 1].charAt(i)){
flag = false;
}
}
if (flag) {
sb.append(strs[0].charAt(i));
}
}
return sb.toString();
}
}
执行结果:
image-20200628180810612

还阔以,官方方法比较丰富,不过时间复杂度大抵相同都是 O(log(mn))