题目 #
Given a non-negative integer num, return true if num can be expressed as the sum of any non-negative integer and its reverse, or false otherwise.
Example 1:
Input: num = 443
Output: true
Explanation: 172 + 271 = 443 so we return true.
Example 2:
Input: num = 63
Output: false
Explanation: 63 cannot be expressed as the sum of a non-negative integer and its reverse so we return false.
Example 3:
Input: num = 181
Output: true
Explanation: 140 + 041 = 181 so we return true. Note that when a number is reversed, there may be leading zeros.
Constraints:
- $0 <= num <= 10^5$
思路1 暴力破解遍历 #
分析 #
- 时间复杂度大致为 $O(n)$
- 暴力,但是带一点分析。如果大于n/2的数,翻转小于自己的,都遍历过了,除非是末尾是0
- 所以对于大于n/2的只用判断是不是整十就好了
代码实现 #
1func reverse(num int) int {
2 result := 0
3 for ; num != 0; num /= 10 {
4 result *= 10
5 result += num % 10
6 }
7 return result
8}
9
10func sumOfNumberAndReverse(num int) bool {
11 for i := 0; i <= num; i++ {
12 if i > num/2 && i%10 != 0 {
13 continue
14 }
15 if i+reverse(i) == num {
16 return true
17 }
18 }
19 return false
20}
思路2 双指针 #
分析 #
- 时间复杂度只和num的位数有关,空间复杂度同样
- 一个数加上它的取反,假设没有进位,可以得到一个中心对称的数字。就算进行进位,也最多进位一位
- 那么我们就从左右两个点开始向内收缩,查看是否可以找到一个数加上翻转自身得到
- 分两种情况
- 进位,那么低位和高位之间相差1
- 没进位,地位和高位一样
- 考虑最高位的情况,如果是1,可能是进位的,也可能是本身加出来的,这两种情况分别计算一下取或即可
- 取pre为左侧前一位是否有进位,suf为右侧是否给后一位进了位,可以得到
- pre存在进位,那么下一轮的suf就存在进位
- pre的值取决于左右两个位是否相差1
- 考虑边界情况
- 如果左侧第一个为1(不考虑1是被进位的情况),右侧最后一位不能为0,否则就会出现
100 => 050 + 050
的情况 - 如果左侧存在进位,那么两个数最大加出来只能到18
- 如果存在进位,那么两个数加起来加上进位最小不可能到0,最大可以到19
- 如果不存在进位,两个数加起来最大到18,最小到0
- 如果左右都符合,到中间一位(181),因为中间的数是自己加自己,那么必须是复数
- 如果没有正中间一位(2321 = 1660 + 0661),遍历到最后,l指向中间偏右一个,r指向中间偏左一个,那么pre和suf应该相等
- 如果左侧第一个为1(不考虑1是被进位的情况),右侧最后一位不能为0,否则就会出现
代码 #
1// s数字的字符串形式
2// l,r 左右指针
3// pre 左侧是否被进位的标识
4func existReverseSum(s string, l, r int, pre int) bool {
5 // 左侧第一个为1,不考虑进位的情况,右侧必须为1,否则就是 100 = 050 + 050的情况
6 if l == 0 && s[l] == '1' && s[r] == '0' {
7 return false
8 }
9 suf := 0 // 右侧是否进位的标识
10 for l < r {
11 checkLeft := int(s[l] - '0')
12 checkRight := int(s[r] - '0')
13 l++
14 r--
15
16 // 存在进位,右侧最小到1
17 if suf == 1 && checkRight == 0 {
18 return false
19 }
20 // 本身要进位,两数相加最多到18,也就是右侧不可能为9(存在进位上面判断过不可能为0,那么就是不存在进位不可能为9)
21 if pre == 1 && suf == 0 && checkRight == 9 {
22 return false
23 }
24
25 if checkLeft == checkRight-suf {
26 // 如果左侧存在进位,那么两个数最大加出来只能到18
27 suf = pre
28 pre = 0
29 } else if checkLeft-1+suf == checkRight {
30 suf = pre
31 pre = 1
32 } else {
33 return false
34 }
35 }
36 if l == r && (int(s[l]-'0')-suf)%2 == 1 {
37 // 13121 中间剩个奇数,就找不到
38 return false
39 } else if l != r && suf != pre {
40 // 21 剩余一个suf没人认领
41 return false
42 }
43 return true
44}
45
46func sumOfNumberAndReverse1(num int) bool {
47 s := fmt.Sprint(num)
48 n := len(s)
49
50 return existReverseSum(s, 0, n-1, 0) || (s[0] == '1' && n > 1 && existReverseSum(s, 1, n-1, 1))
51}