leetcode刷题记录-1447. 最简分数

201 阅读3分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

前言

今日的题目为中等,但是题目给出的数据范围并不大,所有可以直接用循环枚举的暴力解法解出,并不难,只能算是简单题

每日一题

今天的每日一题 1447. 最简分数,难度为中等

  • 给你一个整数 n ,请你返回所有 0 到 1 之间(不包括 0 和 1)满足分母小于等于  n 的 最简 分数 。分数可以以 任意 顺序返回。

示例 1:

输入:n = 2
输出:["1/2"]
解释:"1/2" 是唯一一个分母小于等于 2 的最简分数。

示例 2:

输入:n = 3
输出:["1/2","1/3","2/3"]

示例 3:

输入:n = 4
输出:["1/2","1/3","1/4","2/3","3/4"]
解释:"2/4" 不是最简分数,因为它可以化简为 "1/2"

示例 4:

输入:n = 1
输出:[]

提示:

  • 1 <= n <= 100

题解

暴力解法

由题目的提示中 - 1 <= n <= 100 可以得出题目会给的数据并不是很大,所以能够接受使用暴力的解法,直接将传入的 n 做一个双重循环去模拟里面所以的数为分母并且比它小的数为分子的情况,题目的重点在于,我们存进数组的是一个字符串,所以就没有办法在里面去判断最大公约数,只能在存入之前来判断,要传入的这两个数,他们的最大公约数是否为1,为1的话就满足题目的要求,所以我们需要一个函数,传入两个数字,返回两个数字的最大公约数:

gcd = function (a, b) {
    return b == 0 ? a : gcd(b, a % b);
};

只有当 a%b 为 0 的时候,会把 b 返回出去,这是后返回的值就是两个数的最大公约数。

接着我们输出的答案是一个字符串,所以满足条件的答案我们还需要进行一个拼串的操作。

/**
 * @param {number} n
 * @return {string[]}
 */
var simplifiedFractions = function (n) {
  gcd = function (a, b) {
    return b == 0 ? a : gcd(b, a % b);
  };
  ans = [];
  for (let i = 2; i <= n; i++) {
    for (let j = 1; j < i; j++) {
      if (gcd(i, j) == 1) {
        ans.push(j + "/" + i);
      }
    }
  }
  return ans;
};

image.png

哈希表

我们上面之所以要去判断遍历出来的数组是否是一个最小公约数的原因是最后答案返回的是字符串类型,我们没有办法在答案数组中做一个比较。

但是我们可以通过哈希表加一个中间层,由于我们的两个分子分母都是从小到大递增的,所以我们可以根据遍历的顺序,将碰到的分数值作为key,分数字符串作为value存入哈希表,这样当我们之后碰到跟这个分数值相同但是不是最简的情况,也能够在哈希表中去判断出来已经存在,最后只需要返回哈希表中所有的value

/**
 * @param {number} n
 * @return {string[]}
 */
var simplifiedFractions = function (n) {
  const map = new Map();
  for (let i = 2; i <= n; i++) {
    for (let j = 1; j < i; j++) {
      if (!map.has(j / i)) {
        map.set(j / i, `${j}/${i}`);
      }
    }
  }

  return [...map.values()];
};

image.png