online coding case, since 2020-05-23

2020-05-23
Case 1(easy): 上山下山问题
,上山一步用U表示,下山一步用D表示,起始点和结束点都是sea level。一个从sea level开始的[U,D]序列,求其中经过了几次valley。

思路:vallery中可能有山,但只要山的高度没有超过vallery的深度就可以仍然算作一个vallery。也就是只要sl没有从负值变成0,则可算作一个vallery。sl正时不考虑。设定一个sea level指标sl,每经过一个U则sl+1,经过D则sl-1。当sl+1后等于0,则vallery counter+1.

def countingValleys(n, s):
    if not 0 <= n <= 10**6:
        return 'again'
    cv = 0
    sl = 0
    for st in s:
        if st == 'U':
            sl += 1
            if sl == 0:
                cv +=1
        elif st == 'D':
            sl -= 1
    return cv

Case 2 (medium): 排队相邻交换问题,排队的每个人有从1到n的序号,按顺序发放。但是有人会bribe前面紧邻的一个人交换位置。每个人最多只能bribe两次。先提供一个序列,求出这个队伍中发生了几次bribe使得位置交换成这样。如21534,2 bribed 1(1次),5依次bribed 3/4(2次),累计有3次bribe。但25134这个序列则不满足条件,输出too chaotic,因为5需要bribe超过两次才能到这个位置。
思路1:复杂度为。经过bribe调整后队列上的元素用表示,是在队列上的索引。比较与的大小,并计算比小的元素个数。遍历这个队列,对每个做这样的操作,所有对应的之和。得到的就是bribe调整的次数。注意在测试中一旦则认为too chaotic。
这个问题的假设是每个人只能bribe前面的人,不会bribe后面的人,不然就not make sense了。该思路的缺点是复杂度高。

def minimumBribes(q):
    if not 1 <= len(q) <= 10**5:
        return 'again'
    res = 0
    for i, e in enumerate(q):
        t = max(e-i-1,0)
        if t > 2:
            res = 'Too chaotic'
            break
        if i < len(q) - 1:
            tl = [True for term in q[i+1:] if term-e < 0]
            if sum(tl)>0:
                res += sum(tl)
    print(res)

思路2:一种复杂度为的算法
用到分治法。

(2020.06.06 Sat)
Case 3 (medium): Power Sum问题幂之和问题。给定一个数字X,和幂次数N,找出X可以用多少种N次幂之和的表达形式。1<=X<=1000,2<=N<=10。例: X=100,N=2,输出3,因为共三种表达。提示用recursion。
思路:讨论者给出的思路,智慧得到了成长。

def cal_num(X, N, num):
    if pow(num, N) < X:
        return cal_num(X, N, num+1) + cal_num(X-pow(num,N), N, num+1)
    elif pow(num, N) == X:
        return 1
    else:
        return 0
ans = cal_num(X, N, 1)

(2020.09.21 Mon)
Case 4 Minimal absolute difference in a list 序列中的最小绝对值
原题在这里
一个list中的元素两两计算差的绝对值,找出其中的最小值。
如果从头遍历,则需要计算每个元素与其后的元素的abs diff,复杂度为。降低复杂度,首先可以对元素排序,用复杂度为的排序算法,之后只需遍历一次排序好的序列,计算相邻元素的值,这种算法的复杂度是即。

def min_abs_diff(arr):
    arr = sorted(arr)
    ma = min(abs(x-y) for x,y in zip(arr, arr[1:]))
    return ma

(2020.12.26 Sat)
寻找最大油田。有一片土地,用二维矩阵表示,如果某个地点有石油,则相应的位置用1表示,如果没有石油则0.有石油的土地可能相邻(上下左右),求一片土地上最大的连续油田。
分析:随机检测一块土地(即矩阵中一点),该点有石油,则检测其上下左右四个方向的点有无石油,如果被检测的点在之前已经被访问过,则不检测该点。直到遍历整个矩阵后,找到连接面积最大的油田。
在检测过程中创建一个visited矩阵,记录表示油田的矩阵中对应的点是否被访问过。

def dfs(i,j):
    if i >= 0 and i < row and j >= 0 and j < col and visited[i][j] == None and oil_field[i][j] == 1:
        visited[i][j] = 1
        print('i: ',i,', j: ',j)
        return 1 + dfs(i-1,j) + dfs(i+1,j) + dfs(i,j+1) + dfs(i,j-1)
    else:
        return 0

if __name__ == '__main__':
    oil_field = [ [1, 0, 0, 1, 0, 1, 0], \
                  [0, 1, 1, 1, 0, 1, 0], \
                  [1, 0, 1, 0, 1, 0, 1], \
                  [0, 1, 0, 0, 1, 0, 1], \
                  [1, 1, 1, 0, 1, 0, 1], \
                  [0, 0, 1, 0, 0, 1, 0], \
                  [0, 0, 1, 0, 0, 1, 1], \
                  [1, 1, 1, 1, 1, 1, 1]]
    row, col = len(oil_field), len(oil_field[0])
    visited = [ [None for i in range(col)] for j in range(row)]
    maxof = 0
    for r in range(len(oil_field)):
        for c in range(len(oil_field[0])):
            tmp = dfs(r, c)
            if maxof > tmp:
                continue
            else:
                maxof = tmp
    print(maxof)

(2020.12.27 Sun)
艰难旅行:现已知一个大小为 N · M 的地图,地图中只有可能出现两个数字:0 或 1,现规定如果位于数字为 0 的格子上,则下一步只能往相邻四个格子中数字为 1 的格子走,如果位于数字为 1 的格子上,则下一步只能往相邻四个格子中数字为 0 的格子走。如果给定起点格子,则可以向上下左右四个方向移动,且同一个格子不能重复走,求能在地图中到达多少格子?

1 2 3 4
1 1 0 1 1
2 1 0 1 0
3 0 1 0 1
4 0 0 1 1

比如在上面的案例中以第3行第3列的0为起点,可以到达上下左右的四个点,因为这四点的值都为1,其中的第3行第2列的1又可以到达上下左三点,因为这三点的值与1不同,以此类推。
分析:这种类型可以通过图的BFS来解决。需要visited矩阵记录某个点是否被访问过,也需要判断即将被访问的点是否可当前点的值不同。

def find_neighbours(tmp, data):
    # tmp = (a,b), the index
    row, col =  len(data), len(data[0])
    results = set()
    if 0 <= tmp[0] + 1 < row:
        results.add((tmp[0]+1, tmp[1]))
    if row > tmp[0] - 1 >= 0:
        results.add((tmp[0] - 1, tmp[1]))
    if 0 <= tmp[1]+1 < col:
        results.add((tmp[0], tmp[1] + 1))
    if col > tmp[1]-1 >= 0:
        results.add((tmp[0], tmp[1] - 1))
    return results

if __name__ == '__main__':
    from collections import deque
    import pdb
    data = [ [1, 0, 1, 1, 0],\
             [1, 0, 1, 0, 1],\
             [0, 1, 0, 1, 0],\
             [0, 0, 1, 1, 1] ]
    start_ = (2, 1)
    visited = [[None for i in range(len(data[0]))] for j in range(len(data))]
    q = deque()
    q.append(start_)
    visited[start_[0]][start_[1]] = 1 #注意visited修改的位置,是append之后
    cntr = 0
    result = []
    while q.__len__() != 0:
        tmp = q.popleft()
        cntr += 1
        result.append(tmp)
        neighbours = find_neighbours(tmp, data)
        for n in neighbours:
            if visited[n[0]][n[1]] == None and data[n[0]][n[1]] != data[tmp[0]][tmp[1]]:
                q.append(n)
                visited[n[0]][n[1]] = 1 #append之后即修改visited
    print('cntr: ', cntr)
    print(result)

你可能感兴趣的:(online coding case, since 2020-05-23)