728. 自除数(打表 + 二分)

180 阅读3分钟

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

每日刷题第72天 2021.03.31

728. 自除数

题目描述

  • 自除数 是指可以被它包含的每一位数整除的数。
  • 例如,128 是一个 自除数 ,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
  • 自除数 不允许包含 0 。
  • 给定两个整数 left 和 right ,返回一个列表,列表的元素是范围 [left, right] 内所有的 自除数 。

示例

  • 示例1
输入: left = 1, right = 22
输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
  • 示例2
输入: left = 47, right = 85
输出: [48,55,66,77]

解题思路

  • 根据题意:自除数不允许包含0(即:100、101这样的都不行)。给你一个区间范围,去查找这个区间中的自除数,并将其输出。
  • 暴力模拟:观察数据范围:10^4,计算最坏的情况,10^4 * 10^4 = 10^8也不会超出,因此可以使用暴力模拟。
    • 对于题目中所给的区间中的每一个值,都去判断下其是否为自除数。记区间内所有符合的自除数数组为ans。若当前值是,则加入到数组中,若不是,则判断区间中的下一个值

新的解题思路

  • 打表:提前将所有可能的样例以表格的形式打印出来(在自己本地的电脑上运行),然后再将代码放在leetcode上,此时只需要把样例对应的答案输出即可。
    • 查找对应的样例的答案时间复杂度仅:o(1)
  • 通常打表的使用场景:举例:假设一道题只有一个参数n,这个参数n小于100,但是n = 100的时候,无论什么算法都会超时,这个时候就需要打表。
    • 此时在本地跑出来n = 100时的答案,在写代码的时候只需要查找返回即可。
  • 对于本题来说,你可以将区间[1, 10000]之间的自除数全部打表出来,写代码的时候,直接查找区间内的值进行输出即可。
  • 那么问题来了?如果查找到区间的开始位置呢?
    • 可以使用二分查找,首先数组是有序的,二分查找的时间复杂度o(log(区间[1, 10000]之间的自除数个数)),那么整体的时间复杂度就是o(right - left + 1)
  • 二分查找条件:查找第一个大于等于left的值
    • l:小于
    • r:大于等于
    • 最终的结果返回r即可

AC代码

var selfDividingNumbers = function(left, right) {
  // 自除数不允许包含0,也就是说只要数字中有0均不行
  // 自除数:1位数:自除本身
  // [1,2,3,4,5,6,7,8,9]
  // [11,12,14,15],[22,24],[33,36],[44,48],[55]
  // 2位数:自除百位和各位
  let ans = [];
  function isOwnChu (num) {
    //不包含0
    let numPre = num;
    while(num != 0) {
      // 循环计算每一位
      let wei = num % 10;
      // console.log('wei:', wei)
      if(numPre % wei != 0 || wei == 0){
        return false;  
      }
      num = parseInt(num / 10);
    }
    return true;
  }
  for (;left <= right; left++) {
    // 判断其是否为自除数
    // console.log('left', left)
    if(isOwnChu(left)) ans.push(left)
  }
  return ans;
};

总结

  • 一题多解,可以多多思考下