算法编程题-寻找最近的回文数

算法编程题-寻找最近的回文数

摘要 :本文将对LeetCode 原题 564 寻找最近的回文数进行讲解,并且给出golang语言的实现,该实现通过了所有测试用例且执行用时超过100%的提交,最后给出相关的复杂度分析。
关键词:算法、LeetCode、Golang、分情况讨论

原题描述

LeetCode 564 寻找最近的回文数: 给定一个表示数字的字符串n,求最近的回文数,如果有多个回文数与n的差的绝对值相等,则优先取较小的数。

思路简述

这道题相对比较复杂,没有任何的技巧,只是将所有情况考虑进去,需要分情况讨论所有情况,然后从这些情况下的回文数进行比较,选出最符合条件的。怎么去分情况讨论呢?

要构造一个比较接近的回文数,一种思路是将数都前半部分直接对应到后半部分,这样生成的既是一个回文数,相对来说比较地接近原来的回文数,这种能解决大部分问题,但是还存在一些特殊情况。一种是要将前半部分加一再对应到后半部分,还需要减一再对应到后半部分。此外,加一减一可能导致数位的变化,所以还要将位数减一的最大的回文数和位数加一最小的回文数也加入到待考虑的集合中。更加详细的过程请参考代码实现:

代码实现

go 复制代码
func nearestPalindromic(n string) string {
	nums := []byte(n)
	m := len(nums)
	flag := false
	backUpNums := make([]string, 0)
	for i := m - 1; i >= m/2; i-- {
		if nums[i] != nums[m-1-i] {
			flag = true
			nums[i] = nums[m-1-i]
		}
	}
	if flag { // flag标识是否有修改
		backUpNums = append(backUpNums, string(nums))
	}
	// 考虑将前半部分加一后构造
	c := byte(1)
	for i := m / 2 + m % 2 - 1; i >= 0; i-- {
		nums[i] += c
		if nums[i] > '9' {
			nums[i] -= 10
			c = 1
		} else {
			break
		}
	}
	for i := m - 1; i >= m / 2; i-- {
		nums[i] = nums[m - 1 - i]
	}
	backUpNums = append(backUpNums, string(nums))

	// 考虑将前半部分减一后构造
	nums = []byte(n)
	c = byte(1)
	for i := m / 2 + m % 2 - 1; i >= 0; i-- {
		nums[i] = nums[i] + 10 - c
		if nums[i] > '9' {
			nums[i] -= 10
			break
		} else {
			c = 1
		}
	}
	for i := m - 1; i >= m / 2; i-- {
		nums[i] = nums[m - 1 - i]
	}
	backUpNums = append(backUpNums, string(nums))
	// 再加上两个位数加一减一的回文数
	backUpNums = append(backUpNums, buildMaxPalind(m - 1), buildMinPalind(m + 1))
	res := ""
	for _, num := range backUpNums {
		if res == "" || less(strSub(n, num), strSub(n, res)) || ((strSub(n, num) == strSub(n, res) && less(num, res))) { {
			res = num
		}
	}
	return res
}

func buildMaxPalind(n int) string {
	if n == 0 {
		return "0"
	}
	res := make([]byte, n)
	for i := 0; i < n; i++ {
		res[i] = '9'
	}
	return string(res)
}

func buildMinPalind(n int) string {
	if n == 0 {
		return "0"
	}
	res := make([]byte, n)
	for i := 0; i < n; i++ {
		res[i] = '0'
	}
	res[0] = '1'
	res[n - 1] = '1'
	return string(res)
}

// strSub 字符串加减
func strSub(str1, str2 string) string {
	if str1 == str2 {
		return "0"
	}
	if less(str1, str2) {
		return strSub(str2, str1)
	}
	m := len(str1)
	n := len(str2)
	res := make([]byte, m)
	k := m - 1
	i := m - 1
	j := n - 1
	c := byte(0)
	for i >= 0 || j >= 0 {
		t := str1[i] + 10 - c
		if j >= 0 {
			t -= str2[j]
		}
		if t > 9 {
			t -= 10
			c = 0
		} else {
			c = 1
		}
		if t < '0' {
			t += '0'
		}
		res[k] = t
		k--
		i--
		j--
	}
    for res[k + 1] == '0' && k < m - 1 {
        k++
    }
	return string(res[k+1:])
}

// less 返回str1 是否小于str2
func less(str1, str2 string) bool {
	m := len(str1)
	n := len(str2)
	if m < n {
		return true
	}
	if m > n {
		return false
	}
	for i := 0; i < m; i++ {
		if str1[i] > str2[i] {
			return false
		} else if str1[i] < str2[i] {
			return true
		}
	}
	return false
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),n为字符串数字的长度
  • 空间复杂度: O ( n ) O(n) O(n),也可以实现 O ( 1 ) O(1) O(1)。

参考

相关推荐
颜酱1 小时前
一步步实现字符串计算器:从「转整数」到「带括号与优化」
javascript·后端·算法
离开地球表面_991 小时前
金三银四程序员跳槽指南:从简历到面试再到 Offer 的全流程准备
前端·后端·面试
UrbanJazzerati1 小时前
Scrapling入门指南:零基础也能学会的网页抓取神器
后端·面试
比尔盖茨的大脑1 小时前
事件循环底层原理:从 V8 引擎到浏览器实现
前端·javascript·面试
Qinana2 小时前
从 URL 输入到页面展示:一场跨越进程与协议的“装修”大戏
前端·面试·程序员
我叫黑大帅2 小时前
Go中的interface的两大用法
后端·面试·go
龙猫不热2 小时前
从 0 手写 Promise:拆解 Promise 链式调用的实现原理
前端·javascript·面试
Lee川19 小时前
深度解构JavaScript:作用域链与闭包的内存全景图
javascript·面试
CoovallyAIHub20 小时前
语音AI Agent编排框架!Pipecat斩获10K+ Star,60+集成开箱即用,亚秒级对话延迟接近真人反应速度!
深度学习·算法·计算机视觉
UrbanJazzerati21 小时前
Python Scrapling反爬虫小技巧之Referer
后端·面试