LeetCode双周赛11

LeetCode双周赛11

5088.等差数列中缺失的数字

有一个数组,其中的值符合等差数列的数值规律,也就是说:

在 0 <= i < arr.length - 1 的前提下,arr[i+1] - arr[i] 的值都相等。

我们会从该数组中删除一个 既不是第一个 也 不是最后一个的值,得到一个新的数组 arr。

给你这个缺值的数组 arr,请你帮忙找出被删除的那个数。

示例 1:

输入:arr = [5,7,11,13]
输出:9
解释:原来的数组是 [5,7,9,11,13]。

示例 2:

输入:arr = [15,13,12]
输出:14
解释:原来的数组是 [15,14,13,12]。

提示:

3 <= arr.length <= 1000
0 <= arr[i] <= 10^5

因为是符合等差数列所以如果中间被删去了一个数,那么被删去数两边的差的绝对值(可能是负数)必定比正常两个数间的差的绝对值要大,所以可以记第1和第2间的差再依次比较直到不相等。再比较绝对值大小,就可以得出谁是正常差。

class Solution {
public:
    int missingNumber(vector<int>& arr)
    {
        int n=arr.size();
        int idx1;
        int idx2;
        int pos;
        idx1=arr[1]-arr[0];
        for(int i=1;i<n-1;i++)
        {
            idx2=arr[i+1]-arr[i];
            if(idx1!=idx2)
            {
                pos=i;
                break;
            }
        }
        if(abs(idx1)>abs(idx2))
        {
            return arr[0]+idx2;
        }
        else
        {
            return arr[pos]+idx1;
        }
    }
};

5089.安排会议日程

你是一名行政助理,手里有两位客户的空闲时间表:slots1 和 slots2,以及会议的预计持续时间 duration,请你为他们安排合适的会议时间。

「会议时间」是两位客户都有空参加,并且持续时间能够满足预计时间 duration 的 最早的时间间隔。

如果没有满足要求的会议时间,就请返回一个 空数组。

「空闲时间」的格式是 [start, end],由开始时间 start 和结束时间 end 组成,表示从 start 开始,到 end 结束。

题目保证数据有效:同一个人的空闲时间不会出现交叠的情况,也就是说,对于同一个人的两个空闲时间 [start1, end1] 和 [start2, end2],要么 start1 > end2,要么 start2 > end1。

示例 1:

输入:slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 8
输出:[60,68]

示例 2:

输入:slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 12
输出:[]

提示:

1 <= slots1.length, slots2.length <= 10^4
slots1[i].length, slots2[i].length == 2
slots1[i][0] < slots1[i][1]
slots2[i][0] < slots2[i][1]
0 <= slots1[i][j], slots2[i][j] <= 10^9
1 <= duration <= 10^6

比赛的时候写了个贼复杂的滑动窗口,结果wa了n次都没调出来。。。

其实有更简单的做法,先将这两个序列排序(题目很坑,这两序列不一定是有序的),因为最后结果的区间开头必定是一个现成的,那么就可以边枚举每个阶段的开头,边用一个指针指向另一个序列。每次检查是否相交,如果相交区间是否足够大,如果相交但不够大则将指针后移,如果不相交则枚举下一个区间。

另一个更好写的方法,用双指针,从开始记录两个区间的左最大和右最小(两者相减就是重叠部分),如果某区间的右端最小那么就应该将指针移向下一个(贪心的思想)。

bool cmp(vector<int> a,vector<int> b)
{
    return a[0]<=b[0];
}
class Solution {
public:
    vector<int> minAvailableDuration(vector<vector<int>>& slots1, vector<vector<int>>& slots2, int duration)
    {
        int n1=slots1.size();
        int n2=slots2.size();
        sort(slots1.begin(),slots1.end(),cmp);
        sort(slots2.begin(),slots2.end(),cmp);
        int st;
        int pt1=0;
        int pt2=0;
        int left;
        int right;
        bool getans=0;
        while(pt1<n1 && pt2<n2)
        {
            right=max(slots1[pt1][0],slots2[pt2][0]);
            left=min(slots1[pt1][1],slots2[pt2][1]);
            if(left-right>=duration)
            {
                getans=1;
                st=right;
                break;
            }
            if(left==slots1[pt1][1])
            {
                pt1++;
            }
            else
            {
                pt2++;
            }
        }
        vector<int> ans;
        ans.clear();
        if(getans)
        {
            ans.push_back(st);
            ans.push_back(st+duration);
        }
        return ans;
    }
};

5090.抛掷硬币

有一些不规则的硬币。在这些硬币中,prob[i] 表示第 i 枚硬币正面朝上的概率。

请对每一枚硬币抛掷 一次,然后返回正面朝上的硬币数等于 target 的概率。

示例 1:

输入:prob = [0.4], target = 1
输出:0.40000

示例 2:

输入:prob = [0.5,0.5,0.5,0.5,0.5], target = 0
输出:0.03125

提示:

1 <= prob.length <= 1000
0 <= prob[i] <= 1
0 <= target <= prob.length
如果答案与标准答案的误差在 10^-5 内,则被视为正确答案。

显而易见的概率dp,定义f(i,j)是抛了前i个硬币有j个朝上的概率。

再次显而易见f(i,j)=f(i-1,j-1)*i项朝上的概率+f(i-1,j)*i项朝下的概率

当然本题可以用滚动数组优化,不过数据量很小leetcode内存又能开很大。。。

double f[1005][1005];
class Solution {
public:
    double probabilityOfHeads(vector<double>& prob, int target)
    {
        memset(f,0,sizeof(f));
        int n=prob.size();
        f[0][0]=1.00;
        for(int i=1;i<=n;i++)
        {
            f[i][0]=f[i-1][0]*(1-prob[i-1]);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                f[i][j]+=f[i-1][j-1]*prob[i-1];
                f[i][j]+=f[i-1][j]*(1-prob[i-1]);
            }
        }
        return f[n][target];
    }
};

5111.分享巧克力

你有一大块巧克力,它由一些甜度不完全相同的小块组成。我们用数组 sweetness 来表示每一小块的甜度。

你打算和 K 名朋友一起分享这块巧克力,所以你需要将切割 K 次才能得到 K+1 块,每一块都由一些 连续 的小块组成。

为了表现出你的慷慨,你将会吃掉 总甜度最小 的一块,并将其余几块分给你的朋友们。

请找出一个最佳的切割策略,使得你所分得的巧克力 总甜度最大,并返回这个 最大总甜度。

示例 1:

输入:sweetness = [1,2,3,4,5,6,7,8,9], K = 5
输出:6
解释:你可以把巧克力分成 [1,2,3], [4,5], [6], [7], [8], [9]。

示例 2:

输入:sweetness = [5,6,7,8,9,1,2,3,4], K = 8
输出:1
解释:只有一种办法可以把巧克力分成 9 块。

示例 3:

输入:sweetness = [1,2,2,1,2,2,1,2,2], K = 2
输出:5
解释:你可以把巧克力分成 [1,2,2], [1,2,2], [1,2,2]。

提示:

0 <= K < sweetness.length <= 10^4
1 <= sweetness[i] <= 10^5

一个不太容易想到的方法(大佬除外),按值二分。我们二分巧克力的最小甜度minx,然后检查以当前方法能否分出k+1块,具体怎么检查,就是贪心的划分我们先记一个sum记录一段的和,一但其超过minx就划一块巧克力,这样一直划下去看能不能达到k+1。

为什么这样划分是对的呢?因为我们是检查的最小甜度,超过最小甜度一点点(或者刚好一样)可以使后面的划分地更多,而多出来的就可以分给一个人。

bool check(int minx,vector<int>& sweetness,int k)
{
    int n=sweetness.size();
    int sum=0;
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        sum+=sweetness[i];
        if(sum>=minx)
        {
            cnt++;
            sum=0;
            if(cnt>=k)
            {
                return true;
            }
        }
    }
    return false;
}
class Solution {
public:
    int maximizeSweetness(vector<int>& sweetness, int K)
    {
        K+=1;
        int n=sweetness.size();
        int r=1e9+7;
        int l=0;
        int mid;
        int ans=0;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(check(mid,sweetness,K))
            {
                l=mid+1;
                ans=max(ans,mid);
            }
            else
            {
                r=mid-1;
            }
        }
        return ans;
    }
};

这次比赛打得很惨烈。。。主要还是在t2上磨了太久,果然还是要锻炼码大程序的能力啊。

posted @ 2019-10-20 21:24  黑泽斯  阅读(246)  评论(0编辑  收藏  举报