[路飞]_leetcode-面试题17.09-第k个数

340 阅读4分钟

「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

[题目地址] [B站地址]

有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。

示例 1:

输入: k = 5

输出: 9

本题首先要解决的问题是如何求得更多的素因子只有 3,5,7的数

这里可以从 1 开始,用 1 去和 3,5,7 相乘得到 3,5,7,然后依次对后面的数重复该过程,就得到了更多的素因子只有 3,5,7 的数

将这个过程做到 7 得到的数组如下

[1,3,5,7,9,15,21,15,25,35,21,35]

可以看到这样的情况下我们虽然得到了符合题意要求的数字,但是里面会有重复的情况以及前大后小的情况

题解1

基于上述得到的条件,我们很自然的想到第一种解题思路:

  1. 将每一个值与 3,5,7 相乘得到更多的数字
  2. 将这些数组依次插入到一个数组中
  3. 插入之前需要判断数组中是否有该值,如果有,跳过
  4. 插入数组的时候,不是放到数组末尾,而是找到一个位置,前面的值都小于等于它,后面的值都大于它
  5. 这样找到符合条件的 k 个数,第 k 个就是本题的结果

代码如下:

var getKthMagicNumber = function(k) {
  // 初始化数组
  let arr = [1],
  // 标识当前处理数值的下标
  cur = 0;
  // 当数组中数值数量小于 k*1.3 的时候,求得更多的符合条件的数字
  // 不是k个是因为会出现前大后小的情况,所以第k个值出现的位置是在大于k的位置
  while(arr.length<Math.floor(k*1.3)){
    const num1 = arr[cur]*3,
    num2 = arr[cur]*5,
    num3 = arr[cur]*7;
    if(arr.indexOf(num1)===-1) arr = insert(arr,num1);
    if(arr.indexOf(num2)===-1) arr = insert(arr,num2);
    if(arr.indexOf(num3)===-1) arr = insert(arr,num3);
    cur++;
  }
  return arr[k-1]
  // 将num插入到合适的位置
  function insert(arr,num){
    let cur = arr.length-1;
    while(arr[cur]>num){
      cur--;
    }
    arr.splice(cur+1,0,num);
    return arr;
  }
}

这里要注意的是,因为存在前大后小的情况,所以要找第 k 个值并不是如上处理过程中的第 k 个值,它的出现是要在第 k 个值之后的,这里我么有细致的去算到底要多出多少才会出现正确的第 k 个值,而是粗略的将数量增加了 30%

题解2

上述题解过程中,需要判断当前值是否出现过,而且插入过程中需要将新的数值插入到合适的位置,那么有没有办法直接求得当前位置正确的值呢?

这里我们可以使用如下方法

定义三个指针,分别代表当前 3,5,7每一个乘数要相乘的值在数组中的下标位置 初始化三个指针都指向 0,也就是数组中值为 1 的位置

然后用 3,5,7 分别乘以指针对应值,将三个数字中的最小值确定为当前位置的值

再将本次选定值对应的指针向后走一位

这样,就保证了每次获取的值是后续所有数值中的最小值,将其更新到当前位置,即为当前位置对应的正确的数值

代码如下:

var getKthMagicNumber = function(k) {
  // 初始化数组
  const arr = [1];
  // 初始化三个指针
  let tail3 = tail5 = tail7 = 0;
  for(let i = 1;i<k;i++){
    // 获取每个素因子与其指针对应值的乘积
    const num1 = arr[tail3]*3,
    num2 = arr[tail5]*5,
    num3 = arr[tail7]*7;
    // 将最小值更新为当前位置的值
    arr[i] = Math.min(num1,num2,num3);
    // 将对应指针的位置向后移动一位
    if(arr[i]===num1) tail3++
    if(arr[i]===num2) tail5++
    if(arr[i]===num3) tail7++
  }
  return arr[k-1]
};

这里需要注意的是,因为会有重复的值,所以移动指针的时候,不可以使用 else if,而是都通过 if 判断处理

至此我们就完成了 leetcode-面试题17.09-第k个数

如有任何问题或建议,欢迎留言讨论!