字节跳动2020秋招算法岗笔试(python)

一共4道编程题,限时120min。做了3道。

第一题。

小明早上上学定了N个闹钟,闹钟响起后,选择起床或继续睡等待下一个闹钟响起。已知上课时间和路上花费时间。求小明最晚在哪个闹钟的时间起床。

输入:

  1. N个闹钟
  2. 花费时间(分钟)
  3. 上课时间几时几分
  4. N行,每行都是一个闹钟的时分

输出:
最晚的闹钟的时分

例:

输入:
5
59
06 59
04 00
05 00
06 00
07 00
08 00

输出:
06 00

思路:

首先,用上课时间-花费时间得到最晚起床时间。然后对所有闹钟进行排序后,用二分查找得到最晚起床闹钟。

n = int(input().strip())  # 闹钟个数

clocks = []
for i in range(n):
    clock = [int(x) for x in input().strip().split(" ")]
    clocks.append(clock)
time = int(input().strip())  # 需要时间
deadline = [int(x) for x in input().strip().split(" ")]  # 上课时间

# 上课时间-花费时间 = 最晚起床时间
h = deadline[0]
m = deadline[1] - time
while m < 0:
    h -= 1
    m += 60
deadline = [h, m]

clocks.sort(key=lambda x: (x[0], x[1]))


def less(a, b):
    if a[0] == b[0]:
        return a[1] < b[1]
    else:
        return a[0] < b[0]


def greater(a, b):
    if a[0] == b[0]:
        return a[1] > b[1]
    else:
        return a[0] > b[0]


def print_res(num):
    print(str(num[0]) + " " + str(num[1]))


# 二分法查找
low, high = 0, n
while low <= high:
    mid = (low + high) // 2
    if less(clocks[mid], deadline):  # 如果当前闹钟早于deadline
        if mid < n - 1:  # 如果不是最后一个闹钟
            if greater(clocks[mid + 1], deadline):  # 如果下一个闹钟晚于deadline
                print_res(clocks[mid])
                break
            else:
                low = mid + 1
        else:  # 是最后一个闹钟直接输出
            print_res(clocks[mid])
            break
    elif greater(clocks[mid], deadline):  # 如果当前闹钟晚于deadline
        high = mid - 1
        if high <= 0:
            print_res(clocks[0])
            break

    else:  # 如果当前闹钟等于deadline,直接输出
        print_res(clocks[mid])
        break

第二题

小明和小红发明了一种加密方法。对长度为N的"0/1"字符串S(明文),加密K次。第i次加密就右移i-1次。然后对这K个字符串求异或得到最终的密文。
例如S = “1001010”,K=4。如下
1001010
&ThickSpace; \; 1001010
&ThickSpace; \; &ThickSpace; \; 1001010
&ThickSpace; \; &ThickSpace; \; &ThickSpace; \; 1001010
密文P = “1110100110”
要求写出密文的解密算法,得到明文。

输入:
1.两个数。明文长度N,加密次数K
2.密文

输出:
明文

例:

输入:
7 4
1110100110
输出:
1001010

思路

首先明白异或的性质
1.如果 A ⨁ B = C A\bigoplus B = C AB=C, 那么 B = A ⨁ C B = A\bigoplus C B=AC。相当于三个数已知两个数,就可以异或求第三个数。
2.任何数与0异或得到它本身。
已知密文P的长度是N-K+1。然后,从密文开始分析。比如上面的例子中,明文是1001010,密文是1110100110。那么密文的最后一位是由明文的最后一位与三个0异或得到的。那么密文的最后一位也就是明文的最后一位,由此得到明文的最后一位后。接下来密文的倒数第二位是两个0与明文的倒数第二位与明文的倒数第一位得到的。
也就是
0 ⨁ 0 ⨁ S ( N − 2 ) ⨁ S ( N − 1 ) = P ( N + K − 3 ) 0 \bigoplus 0 \bigoplus S(N-2)\bigoplus S(N-1) = P(N+K-3) 00S(N2)S(N1)=P(N+K3)
由性质2,
S ( N − 2 ) ⨁ S ( N − 1 ) = P ( N + K − 3 ) S(N-2)\bigoplus S(N-1) = P(N+K-3) S(N2)S(N1)=P(N+K3)
由性质1,
S ( N − 2 ) = P ( N + K − 3 ) ⨁ S ( N − 1 ) S(N-2)= P(N+K-3)\bigoplus S(N-1) S(N2)=P(N+K3)S(N1)
同理有,
S ( N − 3 ) = P ( N + K − 4 ) ⨁ S ( N − 1 ) ⨁ S ( N − 2 ) S(N-3)= P(N+K-4)\bigoplus S(N-1) \bigoplus S(N-2) S(N3)=P(N+K4)S(N1)S(N2)

从后往前看,也就是明文的某个数等于它后面明文异或后,再异或上对应位置的密文。但是这个数往后取的位数最多不超过K-1位。比如上面的例子 S ( N − 5 ) = P ( N + K − 6 ) ⨁ S ( N − 2 ) ⨁ S ( N − 3 ) ⨁ S ( N − 4 ) ) S(N-5)= P(N+K-6)\bigoplus S(N-2) \bigoplus S(N-3) \bigoplus S(N-4) ) S(N5)=P(N+K6)S(N2)S(N3)S(N4))这里就舍去了 S ( N − 1 ) S(N-1) S(N1)

如果按照这样的方法,平均每解密一个字符需要进行K次异或操作,一共解密N个字符。所以时间复杂度是 O ( K N ) O(KN) O(KN)
但这样做只通过了50%的case。因为时间复杂度过大导致超时了。

注意到:
S ( N − 5 ) = P ( N + K − 6 ) ⨁ S ( N − 2 ) ⨁ S ( N − 3 ) ⨁ S ( N − 4 ) S(N-5)= P(N+K-6)\bigoplus S(N-2) \bigoplus S(N-3) \bigoplus S(N-4) S(N5)=P(N+K6)S(N2)S(N3)S(N4)
S ( N − 6 ) = P ( N + K − 7 ) ⨁ S ( N − 3 ) ⨁ S ( N − 4 ) ⨁ S ( N − 5 ) S(N-6)= P(N+K-7)\bigoplus S(N-3) \bigoplus S(N-4) \bigoplus S(N-5) S(N6)=P(N+K7)S(N3)S(N4)S(N5)
将等式右边分为A、B两部分,A是对应位置的密文,另一部分B则是前K-1个明文的异或。发现每次B部分其实不需要计算K-1次,只需要用上一次的B部分去掉一个明文异或后再新异或一个明文即可。可是如何去掉一个异或呢,看到性质1,对于S(N-6)的等式上次的B部分B’为 B ′ = S ( N − 2 ) ⨁ S ( N − 3 ) ⨁ S ( N − 4 ) B&#x27; = S(N-2) \bigoplus S(N-3) \bigoplus S(N-4) B=S(N2)S(N3)S(N4),而本次的B部分 B = B ′ ⨁ S ( N − 2 ) ⨁ S ( N − 5 ) B = B&#x27;\bigoplus S(N-2) \bigoplus S(N-5) B=BS(N2)S(N5)。相当于每次只做了两次异或就得到了B部分,而再异或一次A部分就得到了本次的结果。即解密一次最多需要异或3次。而对于倒数K-1位之前的密文,则不需要在B’中去掉一部分。

def xor(a, b):
    if a == b:
        return "0"
    else:
        return "1"


N, K = [int(x) for x in input().strip().split(" ")]
P = input().strip()

S = ""
last_B = "0"
for i in range(K-1, N+K-1)[::-1]:
    num = xor(last_B, P[i])
    S = num + S
    if len(S) >= K:
        last_B = xor(last_B, S[K - 1])
    last_B = xor(last_B, num)

print(S)

第三题

老板给员工发年终奖,员工坐成一排。
条件:1.每个员工至少100元年终奖。2.相邻的员工可以互相得知对方年终奖,在公司年份大的要比在公司年份小的至少多100元,员工才不会有意见。
问:老板怎么发年终奖满足以上条件,并且总和最少。

输入:
1.N个员工
2.每个员工的来公司的年份。
输出:
每个员工的年终奖

例1

输入:
5
7 3 9 6 2
输出:
200 100 300 200 100

例2

输入:
4
1 1 1 1
输出:
100 100 100 100

思路

对于每一个员工都得看他左右连续比他小的员工个数。然后取左右中的最大值。那么它的年终奖等于这个值*100。


N = int(input())
years = [int(x) for x in input().strip().split(" ")]

left = [1] * N  #记录每个员工左边连续比他小的个数
right = [1] * N   #记录每个员工右边连续比他小的个数

for i in range(1, N):
    if years[i] > years[i - 1]:
        left[i] += left[i-1]

for i in range(N-1)[::-1]:
    if years[i] > years[i + 1]:
        right[i] += right[i+1]

for i in range(N):
    years[i] = str(max(left[i], right[i]) * 100)

print(" ".join(years))



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值