NailingPlanks

https://app.codility.com/programmers/lessons/14-binary_search_algorithm/nailing_planks/

You are given two non-empty arrays A and B consisting of N integers. These arrays represent N planks. More precisely, A[K] is the start and B[K] the end of the K−th plank.

Next, you are given a non-empty array C consisting of M integers. This array represents M nails. More precisely, C[I] is the position where you can hammer in the I−th nail.

We say that a plank (A[K], B[K]) is nailed if there exists a nail C[I] such that A[K] ≤ C[I] ≤ B[K].

The goal is to find the minimum number of nails that must be used until all the planks are nailed. In other words, you should find a value J such that all planks will be nailed after using only the first J nails. More precisely, for every plank (A[K], B[K]) such that 0 ≤ K < N, there should exist a nail C[I] such that I < J and A[K] ≤ C[I] ≤ B[K].

For example, given arrays A, B such that:

A[0] = 1 B[0] = 4 A[1] = 4 B[1] = 5 A[2] = 5 B[2] = 9 A[3] = 8 B[3] = 10

four planks are represented: [1, 4], [4, 5], [5, 9] and [8, 10].

Given array C such that:

C[0] = 4 C[1] = 6 C[2] = 7 C[3] = 10 C[4] = 2

if we use the following nails:

  • 0, then planks [1, 4] and [4, 5] will both be nailed.
  • 0, 1, then planks [1, 4], [4, 5] and [5, 9] will be nailed.
  • 0, 1, 2, then planks [1, 4], [4, 5] and [5, 9] will be nailed.
  • 0, 1, 2, 3, then all the planks will be nailed.

Thus, four is the minimum number of nails that, used sequentially, allow all the planks to be nailed.

Write a function:

class Solution { public int solution(int[] A, int[] B, int[] C); }

that, given two non-empty arrays A and B consisting of N integers and a non-empty array C consisting of M integers, returns the minimum number of nails that, used sequentially, allow all the planks to be nailed.

If it is not possible to nail all the planks, the function should return −1.

For example, given arrays A, B, C such that:

A[0] = 1 B[0] = 4 A[1] = 4 B[1] = 5 A[2] = 5 B[2] = 9 A[3] = 8 B[3] = 10 C[0] = 4 C[1] = 6 C[2] = 7 C[3] = 10 C[4] = 2

the function should return 4, as explained above.

Write an efficient algorithm for the following assumptions:

  • N and M are integers within the range [1..30,000];
  • each element of arrays A, B, C is an integer within the range [1..2*M];
  • A[K] ≤ B[K].

思路:二分+前缀和

# you can write to stdout for debugging purposes, e.g.
# print("this is a debug message")

def ok(A,B,C,mid):
    # count values in C
    cnt=[0]*(2*len(C)+1)
    for i in C[:mid+1]: cnt[i]+=1
    
    # prefix sum: accumulate sum of cnt
    for i in range(1,len(cnt)): cnt[i]+=cnt[i-1]
    # if sum between A[i]~B[i] is 0, then plank i can not be covered
    for a,b in zip(A,B):
        if cnt[b]==cnt[a-1]: return False
    return True
    
    

def solution(A, B, C):
    # binary search
    res=float('inf')
    lo,hi=0,len(C)-1
    while lo<=hi:
        mid=(lo+hi)//2
        if ok(A,B,C,mid):
            res=min(res,mid+1)
            hi=mid-1
        else:
            lo=mid+1
    return res if res!=float('inf') else -1


print(solution([1, 4, 5, 8], [4, 5, 9, 10], [4, 6, 7, 10, 2]))

下面的方法set操作可能复杂度会到O(N),所以会TLE

# you can write to stdout for debugging purposes, e.g.
# print("this is a debug message")

def ok(starts,ends,c,ma,ta):
    covered=set()
    done=set()
    c=set(c)
    # iterate from 0 to max value
    for i in range(ma+1):
        covered=covered|set(starts[i]) # current nail will cover more planks
        if i in c: done=done|covered
        covered=covered-set(ends[i]) # remove planks that are out of range
    return len(done)==ta # if cover all planks, return True
            
    
    

def solution(A, B, C):
    # convert interval
    ma = max(B)
    starts=[[] for _ in range(1+ma)]
    ends=[[] for _ in range(1+ma)]
    ba=sorted([(b,a) for a,b in zip(A,B)])
    for i,(b,a) in enumerate(ba):
        starts[a].append(i)
        ends[b].append(i)
    
    # binary search
    res=float('inf')
    lo,hi=0,len(C)-1
    while lo<=hi:
        mid=(lo+hi)//2
#        print(lo,hi)
        if ok(starts,ends,C[:mid+1],ma,len(A)):
            res=min(res,mid+1)
            hi=mid-1
        else:
            lo=mid+1
    return res if res!=float('inf') else -1


#print(set([1,2,3,4,5,6])-set([4,5,6]))
#print(set([1,2,3,4,5,6])|set([7]))
print(solution([1, 4, 5, 8], [4, 5, 9, 10], [4, 6, 7, 10, 2]))

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值