前言
博主最近抖音三面挂在了算法题。复盘时发现是由于遇到陌生的难题,太过紧张,加上以前刷题都是闷着脑袋刷,思路理不清晰,说出思路后,代码编写逻辑也比较混乱。
痛定思痛! 特开每日一题栏目,做每道题时,首先陈述思路,再给出解题代码!
Question
下一个回文数
给定一个数字,返回这个数字的下一个回文数字,以下是几个测试用例:
1 -> 2
121 -> 131
210 -> 212
2233 -> 2332
3322 -> 3333
999 -> 1001
9999 -> 10001
Solution
拿到题目,可以首先可以想到最暴力的解法,即在原数的基础上,不断的+1,然后逐个判断是否是回文数,但是在数字较大的情况下,时间复杂度较高。
比较好一点的解法为,首先将此数字一分为二,将前半段的数字翻转,得到翻转后的数字,随后将前半段数字和翻转后的数字进行拼接,得到result,将此result与原数比较,如果大于原数,就直接返回,如果小于或者等于原数,就将前半段的数字加1后再次进行翻转操作,得到最后的result。
Code
package main
import (
"fmt"
"strconv"
)
func GetNextNum(num int) int {
var result int
var flag bool
//翻转,如果是奇数个数字,需要将最后一位删掉再翻转
var reverse func(s string, flag bool) string = func(s string, flag bool) string {
if flag {
} else {
s = s[:len(s)-1]
}
sbytes := []byte(s)
for i := 0; i < len(s)/2; i++ {
sbytes[i], sbytes[len(s)-i-1] = sbytes[len(s)-i-1], sbytes[i]
}
return string(sbytes)
}
if num < 9 {
return num + 1
}
if num == 9 {
return 11
}
//得到前半段数字
snum := strconv.Itoa(num)
allnum := len(snum) + 1 //如果有进位时,特判
if len(snum)%2 == 0 {
flag = true
snum = snum[:len(snum)/2]
} else {
flag = false
snum = snum[:len(snum)/2+1]
}
//翻转
afternum := reverse(snum, flag)
//拼接
result, _ = strconv.Atoi(snum + afternum)
//比较大小
//如果大于 直接返回
if result > num {
return result
}
//如果小于
//前半段数字+1
prenum, _ := strconv.Atoi(snum)
prenum++
tempnum := strconv.Itoa(prenum)
if len(tempnum) != len(snum) {
//产生了进位
resultnum := ""
for i := 0; i < allnum; i++ {
if i == 0 || i == allnum-1 {
resultnum += "1"
} else {
resultnum += "0"
}
}
result, _ = strconv.Atoi(resultnum)
return result
} else {
snum = tempnum
}
//翻转
afternum = reverse(snum, flag)
//拼接
result, _ = strconv.Atoi(snum + afternum)
return result
//返回
}
func main() {
fmt.Println(GetNextNum(1))
fmt.Println(GetNextNum(121))
fmt.Println(GetNextNum(210))
fmt.Println(GetNextNum(2233))
fmt.Println(GetNextNum(999))
fmt.Println(GetNextNum(9999))
}
总结
拿到题目时,一定要先理清思路,随后选择合适的数据结构来解题,而不是盲目的开始做。比如此题的回文数判断等操作,如果使用int类型去做的话,可以做,但是非常繁琐,容易出错,而换成字符串类型,就可以非常简单的进行翻转、判断等。