数据结构之二分与并查集

二分-LeetCode 287. 寻找重复数

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

示例 1:

输入: [1,3,4,2,2]
输出: 2
示例 2:

输入: [3,1,3,4,2]
输出: 3
说明:

不能更改原数组(假设数组是只读的)。
只能使用额外的 O(1) 的空间。
时间复杂度小于 O(n^2) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。

比较典型的二分查找,但是需要注意右区间ri=mid,而不是ri=mid-1

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n=nums.size();
        int le=1,ri=n-1;
        while(le<ri)
        {
            int mid=(le+ri)/2;
            int cnt=0,l=0,r=0;
            for(int i=0;i<n;i++)
            {
                if(nums[i]<=mid) cnt++;
            }
            if(cnt<=mid) le=mid+1;
            else ri=mid;
        }
        return le;
    }
};

二分-hdu 2899.Strange fuction 

Problem Description

Now, here is a fuction:
  F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100)
Can you find the minimum value when x is between 0 and 100.

Input

The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)

Output

Just the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.

Sample Input

2

100

200

Sample Output

-74.4291

-178.8534

求函数的最小值,先求单调性,只有两种情况:先减后增,一直减.求出fx的导函数f'(x),二分找到f'(x)=0的点即是最小值点.二分的时候需要注意是double型

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
double eps=1e-5;
double y;
double Fx(double x){
    return 6.0*x*x*x*x*x*x*x+8.0*x*x*x*x*x*x+7.0*x*x*x+5.0*x*x-y*x;
}
double fx(double x){
    return 42.0*x*x*x*x*x*x+48.0*x*x*x*x*x+21.0*x*x+10.0*x-y;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lf",&y);
        double l=0.0,r=100.0;
        double ans=Fx(100.0);
        while(r-l>eps){
            double mid=(l+r)/2.0;
            double now=fx(mid);
            ans=min(ans,Fx(mid));
            if(now==0){
                break;
            }
            else if(now>0)
                r=mid;
            else l=mid;
        }
        printf("%.4f\n",ans);
    }
}

并查集-nowcoder 加边的无向图

给你一个 n 个点,m 条边的无向图,求至少要在这个的基础上加多少条无向边使得任意两个点可达~ 

输入描述:

第一行两个正整数 n 和 m 。
接下来的m行中,每行两个正整数 i 、 j ,表示点i与点j之间有一条无向道路。

输出描述:

输出一个整数,表示答案

示例1

输入

4 2
1 2
3 4

输出

1

备注:

对于100%的数据,有n,m<=100000。

虽然只是一道模板题,但是不能仅仅只是为了A题,还有优化,使用路径压缩带来的时间上的节省不是一点点!!!

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,fa[maxn];
void init(){
    for(int i=1;i<=n;i++) fa[i]=i;
}
int find_root(int x){
    int temp,now=x;
    while(x!=fa[x]) x=fa[x];
    while(now!=x){
        temp=fa[now];
        fa[now]=x;
        now=temp;
    }
    return x;
}
void union_both(int u,int v){
    int root_u=find_root(u);
    int root_v=find_root(v);
    if(root_u!=root_v) fa[root_u]=root_v;
}
int main()
{
    int u,v;
    scanf("%d%d",&n,&m);
    init();
    while(m--){
        scanf("%d%d",&u,&v);
        union_both(u,v);
    }
    int ans=0;
    for(int i=1;i<=n;i++) if(fa[i]==i) ans++;
    printf("%d\n",ans-1);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值