最简分数 gcd 25-02-14

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 枚举 #

由于数字不算大,可以采用枚举的方法来求解。问题变成:快速判断两个数组成的分数是否为最简(即判断两个数的最大公约数是否为 1)。

class Solution {
    public int gcd(int x,int y){
        return y>0?gcd(y,x%y):x;
    }
    public List<String> simplifiedFractions(int n) {
        List<String> res=new ArrayList<>();
        if(n<=1)return res;
        for(int i=2;i<=n;i++){
            for(int j=1;j<i;j++){
                if(gcd(i,j)==1){
                    res.add(j+"/"+i);
                }
            }
        }
        return res;
    }
}

复杂度分析

  • 时间复杂度:O(n^2logn)。需要枚举 O(n^2) 对分子分母的组合,每对分子分母计算最大公因数和生成字符串的复杂度均为 O(logn)。
  • 空间复杂度:O(1)。除答案数组外,我们只需要常数个变量。

2 逆用辗转相除法 #

class Solution {
public:
    vector<string> simplifiedFractions(int n) {
        if(n == 1) return {};
        vector<string> answer;
        recusive(ans, 1, 2, n);
        return ans;
    }
private:
    void recusive(vector<string>& ans, int a, int b, int n){   // 逆用辗转相除
        ans.push_back(to_string(a) + '/' + to_string(b));
        if(a+b>n) return; 
        recusive(answer, a, a + b, n);
        recusive(answer, b, a + b, n);
    }
};

作者:cefoperazone
链接:https://leetcode.cn/problems/simplified-fractions/solutions/1339466/by-cefoperazone-x5hp/
来源:力扣(LeetCode
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。