【二分查找】1201. 丑数 III

简介: 二分查找是一种高效的查找算法,其时间复杂度为 O(log n)。在许多情况下,我们需要在一个有序数组中找到某个目标值的搜索范围。本文将介绍一种基于二分查找的搜索范围查找算法,该算法能够快速找到目标值在数组中的起始和结束位置。

【二分查找】1201. 丑数 III

前言

二分查找是一种高效的查找算法,其时间复杂度为 O(log n)。在许多情况下,我们需要在一个有序数组中找到某个目标值的搜索范围。本文将介绍一种基于二分查找的搜索范围查找算法,该算法能够快速找到目标值在数组中的起始和结束位置。

在另一篇博客里讲过二分法的模板:

《二分法的模板讲解》


🕺作者: 迷茫的启明星


学习路线

C语言从0到1

C++初阶

数据结构从0到1

😘欢迎关注:👍点赞🙌收藏✍️留言


🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢阅读!!!


问题背景

给定四个整数:n、a、b、c,我们需要设计一个算法来找出第n个丑数。丑数是指可以被a、b或c整除的正整数。


原题链接

https://leetcode.cn/problems/ugly-number-iii/description/


问题分析

为了解决这个问题,我们可以利用容斥原理来计算区间 [1, mid] 内的丑数个数。容斥原理是组合数学中的一个核心概念,用于计算多个集合的并集的元素数量。在本问题中,我们需要计算被 a、b、c 整除的正整数数量,以及被 ab、ac、bc 整除的正整数数量。然后,从总个数中减去被 ab、ac、bc 整除的正整数数量,最后再加上被 abc 整除的正整数数量。


算法实现

首先,我们需要计算a、b、c的最小公倍数abc,以及ab、ac、bc的最小公倍数。


初始化结果范围为[min({a, b, c}), 2 * 10^9]。


使用二分查找法,在[l, r]范围内查找第n个丑数。


在每次迭代中,计算中间值mid,并使用容斥原理计算[1, mid]中的丑数个数。


根据丑数个数与n的大小关系,更新搜索范围。


当搜索范围收缩到l+1 == r时,返回r作为第n个丑数。


代码

class Solution {
public:
    typedef long long ll;
    // greatest common divisor 最大公约数
    ll gcd(ll a, ll b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    // least common multiple 最小公倍数
    ll lcm(ll a, ll b) {
        return a * b / gcd(a, b);
    }
    int nthUglyNumber(int n, int a, int b, int c) {
        ll ab = lcm(a, b), ac = lcm(a, c), bc = lcm(b, c);
        ll abc = lcm(ab, c);
        //本题结果在 [1, 2 * 10^9] 的范围内,优化为 [min({a,b,c}), 2 * 10^9]
        ll l = min({a,b,c})-1, r = 2e9+1; 
        while (l+1 != r) {
            ll mid = (l+r)>>1;
            // 容斥原理:计算 cnt 为[1,mid]中的丑数个数
            ll cnt = mid / a + mid / b + mid / c - mid / ab - mid / ac - mid / bc + mid / abc;
            if (cnt < n) {
                l = mid;
            } else {
                r = mid;
            }
        }
        return (int)r;
    }
};



总结

本文介绍了一种高效的算法来解决求解第n个丑数的问题。通过使用容斥原理和二分查找法,我们可以在较短的时间内找到第n个丑数。在实际应用中,这种算法可以应用于各种需要求解丑数的场景,提高计算效率。


本文由mdnice多平台发布


相关文章
|
6月前
LertCode263.丑数
LertCode263.丑数
25 1
|
7月前
|
算法 测试技术 C#
[二分查找]LeetCode2040:两个有序数组的第 K 小乘积
[二分查找]LeetCode2040:两个有序数组的第 K 小乘积
|
7月前
|
测试技术
leetcode-152:乘积最大子数组
leetcode-152:乘积最大子数组
64 0
|
7月前
|
C++
丑数(C++)
丑数(C++)
57 0
|
算法 测试技术 C++
C++算法:二分查找旋转数组
C++算法:二分查找旋转数组
二分法查找(折半查找)
二分法查找(折半查找)
79 0
|
机器学习/深度学习 存储 人工智能
“二分“==“二分查找“ ?“yes“:“no“;
“二分“==“二分查找“ ?“yes“:“no“;
128 0
|
算法 Java C++
二分查找(折半查找)
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。
159 0
二分查找(折半查找)
|
机器学习/深度学习
475. 供暖器 : 二分双指针运用题
475. 供暖器 : 二分双指针运用题