【算法】Find the Closest Palindrome 寻找最近的较小回数

Find the Closest Palindrome 寻找最近的较小回数

题目

Given an integer n, find the closest integer (not including itself), which is a palindrome.

The ‘closest’ is defined as absolute difference minimized between two integers.

Example 1:
Input: “123”
Output: “121”
Note:
The input n is a positive integer represented by string, whose length will not exceed 18.
If there is a tie, return the smaller one as answer.

  1. 长度不超过18
  2. 个位数(0 ~ 9)都是回数
  3. 若有两个回数与原数字距离相同,返回较小的
  4. 返回的回数不能是原数字本身

解题思路

  1. 若原数字为个位数,则返回原数字 -1 的数字,若不在 0 ~ 9范围内,则返回原数字+1的数字
  2. 若原数字非个位数,则有以下五种情况的回数
    1. 升位回数:1(n-1个0)1
    2. 降位回数:n-1个9
    3. 中间数+1后,将左侧字符串逆序进行拼接
    4. 中间数不变,将左侧字符串逆序进行拼接
    5. 中间数-1后,将左侧字符串逆序进行拼接
  3. 遍历回数集合,筛除原数字,并依据与原数字差值绝对数找到合适回数返回

Tips:

  • n为字符串长度
  • 中间数:
    • 若字符串长度为奇数,则中间数为正中间的数
    • 若字符串长度为偶数,则中间数为左侧字符串的最后一个字符,在进行拼接时,需将左侧字符串最后一个字符替换成中间数后再进行拼接

代码实现

    class func NearestPalindromicSolution(_ n: String) -> String{
//        获取字符串长度
        let len = n.count
//        若字符串长度为个位数,为0则返回1,不为0则返回小于其1的值
        if len<2 {
            var num = Int(n)!
            num = num == 0 ? 1:num-1
            return String(num)
        }
//        判断是有中间字符
        let hasMid = (len%2 == 0) ? false : true
//        获得中间字符或中间左侧的位置
        let midNum = hasMid ? (len / 2) : (len / 2 - 1)
//        获得中间字符或中间左侧的index
        let midIndex = n.index(n.startIndex, offsetBy: midNum)
//        获得中间字符右侧的index
        let midIndexR = n.index(midIndex, offsetBy: 1)
//        获得中间字符左侧的index,但若中间字符为首字符则获取中间字符
        let midIndexL = midNum > 0 ? n.index(midIndex, offsetBy: -1) : midIndex
//        获得左侧字符串
        let leftStr = hasMid ? String(n[n.startIndex ... midIndexL]) : String(n[n.startIndex ... midIndex])
//        获得右侧字符串
        var rightStr = String(n[midIndexR ..< n.endIndex])
//        将右侧字符串逆序
        rightStr = String(rightStr.reversed())
//        获得中间字符
        var midStr = String(n[midIndex])
//        创建SET容器
        var set = Set<Int>()
//        创建数组,用于与中间数字加减1和0用
        let arr = [-1, 0, 1]
//        获得中间字符的数字
        let mid = Int(midStr)!
//        遍历数组
        for e in arr{
//            将中间数字加减1和0
            let num = mid + e
//            若结果在0~9范围内,则有效
            if (num>=0) && (num<=9){
//                获得加减1和0后的数字并字符串化
                midStr = String(num)
//                将左侧字符串,中间字符,左侧字符串的逆序拼接起来
                var str = leftStr + midStr + String(leftStr.reversed())
//                若是没有中间字符,则应该讲中间字符替换掉左侧字符串的最后一个字符,并将左侧字符及其逆序拼接起来
                if !hasMid {
                    str = leftStr
//                    str = leftStr + String(leftStr.reversed())
//                    str.replaceSubrange(midIndex ... midIndexR, with: midStr+midStr)
                    str.remove(at: midIndex)
                    str = str + midStr + midStr + String(str.reversed())
                }
//                将与原字符串不相同的结果插入SET容器
                if str != n{
                    set.insert(Int(str)!)
                }
            }
        }
//        算出升位和降位的最近回数,并插入SET容器
        let a = Int(pow(Double(10), Double(len)) + 1)
        let b = Int(pow(Double(10), Double(len-1)) - 1)
        set.insert(a)
        set.insert(b)
//        获取源字符串的数字
        let numOri = Int(n)!
//        声明最小回数和偏差
        var minNum = -1
        var minOffset = -1
//        遍历SET容器,将元素与原数字比较,获取最近回数
        for el in set {
            let offset = abs(numOri - el)
            if(minOffset == -1)||(minOffset > offset){
                minOffset = offset
                minNum = el
            }else if(minOffset == offset){
//                如果有两个回数的偏差相同,取较小值
                minNum = min(minNum, el)
            }
        }
//        返回最近且较小的回数字符串
        return String(minNum)
    }

代码地址:https://github.com/sinianshou/EGSwiftLearning

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值