整数二分习题:力扣-367(含思路详解,定义数据类型详解),洛谷-2249

文章介绍了使用二分查找算法解决两个编程题目:力扣367题,通过二分查找判断一个数是否为完全平方数;洛谷2249题,寻找序列中目标元素首次出现的索引。对于完全平方数问题,讨论了整数二分的细节,包括处理溢出和数据范围。另一个解决方案利用数学性质,通过不断减去奇数判断是否为完全平方数。在洛谷题目中,明确了二分查找的性质是向左查找大于等于目标值的元素。
摘要由CSDN通过智能技术生成

目录

 1.力扣-367

思路 

数据范围

二分代码如下

直呼优雅!

代码如下

2.洛谷-2249


 1.力扣-367

思路 

通过之前浮点数二分例题:数的三次方根 的基础上,我们就很容易能想到这种开方的题思路实质是二分的。(额,突然发现之前写过求x平方根的题解,算啦再多解释一下)

虽然用浮点数二分写这道题更直观更准确,但是这道题要求是定义为整数,所以我们要按要求来。首先要先找到二次方根,相较浮点数二分,我们要多考虑一点性质的划分条件,这道题进行二分的性质应该是,找到第一个 平方之后的数 小于所给的数(这里是因为,向下取整的原因[下面会详细解释],我们尽量往小的数上找,即尽量向左找)。

接着在考虑如何判断是否是完全平方数,如果一个数不是完全平方数,开方之后应该是有小数,但是我们既然是整数二分,那么所得到的数肯定是一个整数,那到底应该怎么判断是不是呢?这时候我们想到由于整型除法的取整方式是向下取等,也就是说2.多的会得出2,这说明如果这个数不是完全平方数,那么我们在循环结束得到取整后的二次方根记为 l (因为循环结束的时候 l=r=mid),再多写一个if语句,判断刚刚得到的 l*l 和 x 的大小关系,如果< 则说明不是完全平方数,那么返回false ,否则返回true。想一下可以理解哈。

思路明白了哈。

数据范围

num 的最大值是2^31-1,那么开根号,最大应该是46340。

r 的初始值为 num,所以它的最大值为 2147483647。但是,在二分查找过程中,r 的值会不断减小,最终不会超过 46340。但是当 r 的值大于 46340 时,mid 的值也会大于 46340。所以mid类型应该定义成 long long类型。后面的1ll 就表示把这个表达式转换成long long类型

int mid = (l + r + 1ll) / 2;

同时在后面,mid*mid 的结果将超过最大值,导致溢出。所以在while循环中的if判断条件写成除法形式避免溢出

但是最终判断是否时完全平方数的时候,if 条件可以写成乘法形式,是因为在二分查找过程中,当 r 的值大于 46340 时,总会执行 r=mid-1; 这一行代码,使得 r 的值不断减小。最终,r 的值不会超过 46340。由于 l 的值始终小于等于 r,所以 l*l 不会溢出

二分代码如下

#include <iostream>
using namespace std;
class Solution
{
public:
    bool isPerfectSquare(int num)
    {
        int l = 0, r = num;
        while (l < r)
        {
            int mid = (l + r + 1ll) / 2;
            if (mid <= num / mid)
                l = mid; 
            else
                r = mid - 1; 
        }
        // cout<<l<<endl;
        if (l * l < num)
            return false;
        else
            return true;

        /* 如果想用除法的书写形式,注意由于向下取整,我们必须再多判断一下余数是不是0 才能确定是不是完全平方数
        if(l==num/l && num%l==0)return true;
        else return false;
        */
    }
};
int main()
{
    int x;
    cin >> x;
    Solution s;
    bool ans = s.isPerfectSquare(x);
    cout << ans << endl;
    return 0;
}

 ok这道题先到这。

直呼优雅!

奥对了在讨论区看到个巨牛的数学思路。

4=1+3 9=1+3+5 16=1+3+5+7。可以看出完全平方数都是由奇数相加而得,那么就可以使用一个while循环,不断减去一个从1开始不断增大的奇数,若最终减成了0,说明是完全平方数,否则,不是。

其原理就是:(n+1)^2-n^2=2n+1

代码如下

#include <iostream>
using namespace std;
class Solution 
{
public:
    bool isPerfectSquare(int x) 
    {
        int num = 1;
        while(x > 0) 
        {
            x -= num;
            num += 2;
        }
        return x == 0;
    }
};
int main()
{
    int x;
    cin >> x;
    Solution s;
    bool ans = s.isPerfectSquare(x);
    cout << ans << endl;
    return 0;
}

我直接惊呼!!太优雅了!!

2.洛谷-2249

这道题思路也不难,题中要求输出该数字在序列中第一次出现的编号,由此我们可以确定二分的性质是,向左找,找到第一个>=目标元素的值。

写了那么多次了,模板就不再解释了哈。

直接上代码

#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N];
int n,m,q;
int find(int q)
{
    int l=1,r=n;
    while(l<r)
    {
        int mid=l+(r-l)/2;
        if(a[mid]>=q)r=mid;
        else l=mid+1;
    }
//找到就返回下标,没找到返回-1
    if(a[l]==q)return l;
    else return -1;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    while(m--)
    {
        cin>>q;
        int ans=find(q);
        cout<<ans<<" ";
    }
    return 0;
}

(稍微提一嘴,我是在vscode上写代码,之后复制到洛谷上的,这样是过不了的,tab键出现问题,嗯,有大佬清楚这个问题的话求指点!!)(上面这个没问题!)

哇哦,第一次题解写这么短(hhhh服了我了) 说明什么?practice makes perfect!!(好中二hhhh)


ok啦,这次先写两道题,二分这部分还有两个习题。留到下一篇写把。感觉有个题比较难懂。

有问题欢迎指出哦,非常感谢!!

也欢迎交流和建议奥。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值