「这是我参与2022首次更文挑战的第24,活动详情查看: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 <= nums.length <= 100 数组长度较短;要想是最简分数的话分母肯定不能为1 分子肯定不能为n,只有这样才能保证是分数。
当 n = 4 我们可以看到1/2与2/4的计算结果是一样,只要我们保证1/2比2/4先出,也就是结合map对象判断当前只是存在就能判断出当前分数是否是最简分数。
除了上述方法我们还可以通过辗转相除的方法先解决此问题。
我们先来复习一下辗转相除当 n = 10 时,假设分子是8,分母是10
10 % 8 是 2
8 % 2 是 0
此时2就是8与10的最大公因数,所以说8/10不是最简分数。
分步实现 利用map
定义 map 存放 值与式子的关系(0.5,1/2),定义 ans用于存放当前符合最简分数的式子。
const map = new Map();
const ans = []
我们通过俩层循环来计算结果。第一层循环中的i表示分子取值范围为[1,n); 第二层循环中的i表示分母取值范围为[2,n];
使用lab存放计算结果,使用val存放式子。
for(let i = 1;i<n;i++){
for(let j = i+1;j<=n;j++){
let lab = i/j
let val = `${i}/${j}`
}
}
判断当前结果是在map里是否存在,如果存在说明不是最简分母;不存在时将式子存入ans中,值与式子的关系存入map中。
for(let i = 1;i<n;i++){
for(let j = i+1;j<=n;j++){
let lab = i/j
let val = `${i}/${j}`
if(!map.has(lab)){
map.set(lab,val);
ans.push(val)
}
}
}
代码实现 利用map
/**
* @param {number} n
* @return {string[]}
*/
var simplifiedFractions = function(n) {
const map = new Map();
const ans = []
for(let i = 1;i<n;i++){
for(let j = i+1;j<=n;j++){
let lab = i/j
let val = `${i}/${j}`
if(!map.has(lab)){
map.set(lab,val);
ans.push(val)
}
}
}
return ans;
};
分布实现
首先我们先实现一个辗转相除的方法。
const gcd = (a, b) => {
while(b){
[a,b] = [b,a % b]
}
return a
};
当辗转相除的方法返回的结果为1时说明是最简分数。
let ans = [];
for (let i = 1; i < n; i++) {
for (let j = i + 1; j <= n; j++) {
if (gcd(i, j) == 1) ans.push(`${i}/${j}`);
}
}
return ans;
代码实现 辗转相除
/**
* @param {number} n
* @return {string[]}
*/
var simplifiedFractions = function (n) {
const gcd = (a, b) => {
while(b){
[a,b] = [b,a % b]
}
return a
};
let ans = [];
for (let i = 1; i < n; i++) {
for (let j = i + 1; j <= n; j++) {
if (gcd(i, j) == 1) ans.push(`${i}/${j}`);
}
}
return ans;
};