字节跳动8.12机试五道编程题_Nelson
第一题:
在[m,n]的矩阵中,只有1,0元素。定义相邻包括:上,下,左,右,左上,左下,右上,右下八个点,求连通区域的数量,以及最大连通区域中元素1的个数。
解法:递归回溯
Python Code:
import sys
a = sys.stdin.readline().strip().split(',')
m = int(a[0])
n = int(a[1])
d = []
num = []
pp = []
for i in range(m):
a = sys.stdin.readline().strip().split(',')
d.append(a)
flag = []
for i in range(m):
p = [0]*n
flag.append(p)
def fun(d,i,j):
if i>=m or j>=n or i<0 or j<0:
return 0
if d[i][j] =='0' or flag[i][j] ==1:
return 0
global count
count += 1
flag[i][j] = 1
fun(d, i - 1, j - 1)
fun(d, i - 1, j)
fun(d, i - 1, j + 1)
fun(d, i, j - 1)
fun(d, i, j + 1)
fun(d, i + 1, j - 1)
fun(d, i+1, j)
fun(d, i + 1, j + 1)
for i in range(m):
for j in range(n):
if d[i][j] == '1' and flag[i][j] == 0:
count = 0
fun(d, i, j)
num.append(count)
print(len(num), end=',')
print(max(num))
第二题:
为了提高文本质量…求众多区间合并,相当于求多个区间的并集
思路:排序后合并
Python Code:
def fun(data):
data = sorted(data)
result = []
index = 0
for i in range(1,len(data)):
if data[i-1][1] >= data[i][0]:
continue
result.append([data[index][0], data[i-1][1]])
index = i
result.append([data[index][0], data[i][1]])
return result
data = [[11,12],[8,10],[1,4],[2,8]]
print(fun(data))
第三题:抽牌游戏
抽牌游戏,每张拍有(x,y),A,B分别抽,A(x)代表A手里所有牌x的和,B(x)代表B手里所有牌x的和。求A(x)==b(x)时,A(y)+B(y)的最大值,
思路:动态规划利用动态规划,维护一个数组buf[],size = 2*sum(x)+1。buf[i]存放的是A(X)-B(X)+sum(x) = i时,A(y)+B(y)的最大值。这里+sum(x)是为了保证index大于0。以sum(x) = 4 为例size=9,index= 0-8:
[0, 1, 2, 3, 4, 5, 6, 7, 8] ——–> A(X)-B(X)+sum(x)
[-4, -3, -2, -1, 0, 1, 2, 3, 4] ——–> A(X)-B(X)
所以动态维护该数组,最终输出buf[sum(x)] 代表差为0时,A(y)+B(y)的最大值。
buf[i] = max( buf[i], buf[i-x[j]], buf[i+x[j]] )
括号中:buf[i]代表x[j] A、B都不拿;buf[i-x[j]]代表 A 拿x[j];buf[i+x[j]]代表 B 拿x[j]。
Python Code:
def fun(data):
n = len(data)
x = []
y = []
for i in data:
x.append(i[0])
y.append(i[1])
sum_x = sum(x)
buf = [-float('inf')] * (2 * sum_x + 1)
buf[sum_x] = 0
num = len(buf)
for i in range(n):
b = buf.copy()
for j in range(num):
if j + x[i] < num:
buf[j] = max(b[j], b[j + x[i]] + y[i])
if j - x[i] >= 0:
buf[j] = max(buf[j], b[j - x[i]] + y[i])
return buf[sum_x]
a = [[3, 1], [2, 2], [1, 4], [1, 4]]
print(fun(a))
第四题:统计满足条件的区间个数
两个同样大小的数组,a,b。统计MAX(a[l,k]) < MIN(b[l,k])的总数,即是在某一段相同始末位置的子数组中,a的该子数组的最大值如果小于b的对应的子数组的最小值则计数1。
思路:对于[l , k]区间来说,随着k变大 max( a[l,k+1] )>=max( a[l,k] ),
min(b[l,k+1])<=min(b[l,k])。这两条单调的性质意味着找到最大的k,使得:
max(a[l,k]) < max(b[l,k]),计数器加(k - l + 1). 利用二分法,复杂度为O(nlog(n)).
Python Code:
def fun(a,b):
n = len(a)
num = 0
for i in range(n):
left = i
right = n-1
while left <= right:
mid = left + (right - left)//2
if max(a[i:mid+1]) >= min(b[i:mid+1]):
right = mid - 1
else:
left = mid + 1
if max(a[i:mid+1]) < min(b[i:mid+1]):
num += mid - i + 1
else:
num += mid - i
return num
a = [1,1,2,1,1,1]
b = [1,2,3,4,5,6]
print(fun(a,b))
第五题:主播问题,
贪心算法,类似于背包,在此基础上加滑动指针。复杂度O(n2)
Python Code:
def fun(data, m):
x = []
for item in data:
if item[0] < item[1]:
x.append([item[0], item[1]])
x.append([item[0]+m, item[1]+m])
else:
x.append([item[0], item[1] + m])
x.append([item[0] + m, item[1] + m + m])
x = sorted(x, key=lambda k: k[1])
res = 0
for i in range(len(x)):
num = 1
index = i
for j in range(i, len(x)):
if x[j][1] - x[i][0] > m:
break
if x[j][0] >= x[index][1]:
num += 1
index = j
if num > res:
res = num
return res
if __name__ == '__main__':
data = [[0,1],[2,7],[6,9]]
print(fun(data,10))
-另外一种方法O(n)复杂度,利用两个索引,把数据控制在一天内
def fun(data, m):
x = []
for item in data:
if item[0] < item[1]:
x.append([item[0], item[1]])
x.append([item[0]+m, item[1]+m])
else:
x.append([item[0], item[1] + m])
x.append([item[0] + m, item[1] + m + m])
x = sorted(x, key=lambda k: k[1])
res = 0
num = 1
first = 0
index = 0
for i in range(1,len(x)):
if x[i][1] - x[first][0] > m:
first += 1
if num > res:
res = num
continue
if x[i][0] >= x[index][1]:
num += 1
index = i
return res
if __name__ == '__main__':
data = [[0,5],[2,7],[3,9]]
print(fun(data,10))
总结:
部分代码没有按照题目中的标准输入输出,只给出了核心代码。代码只测试过少量数据,如有问题,欢迎留言指正。