Bootstrap

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

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

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

原题描述

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

思路简述

这道题相对比较复杂,没有任何的技巧,只是将所有情况考虑进去,需要分情况讨论所有情况,然后从这些情况下的回文数进行比较,选出最符合条件的。怎么去分情况讨论呢?
要构造一个比较接近的回文数,一种思路是将数都前半部分直接对应到后半部分,这样生成的既是一个回文数,相对来说比较地接近原来的回文数,这种能解决大部分问题,但是还存在一些特殊情况。一种是要将前半部分加一再对应到后半部分,还需要减一再对应到后半部分。此外,加一减一可能导致数位的变化,所以还要将位数减一的最大的回文数和位数加一最小的回文数也加入到待考虑的集合中。更加详细的过程请参考代码实现:

代码实现

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)

参考

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;