564. 寻找最近的回文数

333 阅读4分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

不是因为看到了希望才坚持,而是因为坚持了才能看到希望。共勉

每日刷题第53天 2021.03.02

564. 寻找最近的回文数

题目描述

  • 给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。
  • “最近的”定义为两个整数差的绝对值最小。

示例

  • 示例1
输入: n = "123"
输出: "121"
  • 示例2
输入: n = "1"
输出: "0"
解释: 0 和 2是最近的回文,但我们返回最小的,也就是 0。

思路分析

  1. 这道题不难,主要考察的是:细心,一些边界问题比较容易出错
  2. 一共wa了5次,遇到了一些问题。刚开始的时候,想的是截取前半段的数据将其翻转后,拼接在后面即可。

错误样例分析

  • "10"遇到导致回文整数位数变少的情况,例如此时的正确输出为:"9",从两位数变成了1位数。
  • "100"同上,是一样的位数减少导致的问题。此时修改代码,需要预判下位数减少和位数增加的情况
    • "10" => "9"位数减少
    • "99" => "101"位数增加
  • "1283"
  • "1837722381"存在两个和n的差值相同的情况,那么就需要取较小的那个,出错原因:比较的时候,就默认了顺序,因此就算前面的数比后面的小,也不能算上。解决:调整比较顺序,将最小的值放在最前面,最大的值放在最后面进行比较。
  • "1805170081"同上错误原因。

AC代码

/**
 * @param {string} n
 * @return {string}
 */
var nearestPalindromic = function(n) {
  let len = n.length;
  // 长度小于1,表示回文数是-1
  if(len == 1) return n - 1 + '';
  // 讨论长度大于1的情况
  let ans = '';
  // 预处理:位数减少1 或者 增加1 的情况
  // 最小值
  let multi = Math.pow(10, len - 1);
  if(Number(n) <= multi + 1){
    ans += multi - 1;
    return ans;
  }
  // 最大值
  let max = Math.pow(10, len);
  if(Number(n) + 1 == max){
    ans += max + 1;
    return ans;
  }

  // 封装查最小差值函数
  function minCha (oneStr, twoStr, threeStr) {
    // flag用于标记,那个差值最小
    let flag = 0;
    if(Math.abs(n - oneStr) <= Math.abs(n - twoStr)){
      flag = 1;
    }else {
      flag = 2;
    }
    if(flag == 1){
      if(Math.abs(n - oneStr) <= Math.abs(n - threeStr)){
        flag = 1;
      }else {
        flag = 3;
      }
    }else if(flag == 2) {
      if(Math.abs(n - twoStr) <= Math.abs(n - threeStr)){
        flag = 2;
      }else {
        flag = 3;
      }
    }
    if(flag == 1){
      return oneStr;
    }else if(flag == 2){
      return twoStr;
    }else {
      return threeStr;
    }
  }
  // 分奇偶进行讨论
  let mid = len / 2;
  // 偶数
  if(len % 2 == 0){
    // 从开头截取到中间位置
    let preStr = n.substr(0,mid);
    // 从中间的位置截取到最后
    let lastStr = n.substring(mid);
    let contra = lastStr.split('').reverse().join('');
    // 1.情况:自身就是回文数
    if(preStr == contra){
      let one = Number(preStr) - 1 + '';
      let two = one.split('').reverse().join('');
      ans += one + two;
    }else {
      // 2.自身不是回文数(最开始的错误想法:xxxx尽量改变的是后面的数,保留前面的数不变xxxx)
      // 正确思路:需要判断哪边的值更小 -1 / 0 / +1
      // 0
      let num = Number(preStr);
      // -1
      let one = num - 1 + '';
      // +1
      let three = num + 1 + '';
      let oneStr = one + one.split('').reverse().join('');
      let twoStr = num + (num + '').split('').reverse().join('');
      let threeStr = three + three.split('').reverse().join('');
      // 封装函数
      ans = minCha(oneStr, twoStr, threeStr);
    }
  }else {
    // 从开头截取到中间位置
    let preStr = n.substr(0,mid);
    // 从中间的位置截取到最后
    let midStr = n.charAt(mid);
    let lastStr = n.substring(mid + 1);
    let contra = lastStr.split('').reverse().join('');
    // 1.情况:自身就是回文数
    // 12121,中间的数-1,如果为0那么就+1
    if(preStr == contra){
      let num = Number(midStr);
      if(num == 0){
        num++;
      }else {
        num--;
      }
      ans += preStr;
      ans += num;
      ans += preStr.split('').reverse().join('');
    }else {
      // 不是回文数
      let newPre = n.substr(0, mid + 1);
      let num = Number(newPre);
      let one = num - 1 + '';
      let three = num + 1 + '';
      let oneStr = preStr + one.split('').reverse().join('');
      let twoStr = preStr + (num + '').split('').reverse().join('');
      let threeStr = preStr + three.split('').reverse().join('');
      ans = minCha(oneStr, twoStr, threeStr);
    }
  }
  return ans;
};

总结

  • 下次再遇到给当前的数+1/-1/0这样的情况,一定要预先排好顺序,即-1/0/+1,可实现差值相同,取到最小值的情况。
  • 做题需要思考问题,并且能够用想到的方法解决下手头的样例,大致想清楚怎么解题,再开始动手。不然只能缝缝补补,冒怼冒碰,这样的提升并不大。
  • 遇到一些比较难的,(针对自己)比如本题的三个数相互比较,选择哪一个,下意识就觉得很难,不想写,想去查看题解。以后再遇到这样的情况也要像今天一样,自己手写出来,不要怕麻烦,然后再去看别人写的题解,优化自己的代码。

求指点

  • 感觉自己写的代码整理之后,还是很长,各位大佬,如果有优化建议,可以直接留言,非常感谢,共同进步!