【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手

文章目录

  • 20190819 商汤
    • 3. papers reading
    • 4. 手动求导
  • 20190822 美团
    • 1. 字符串排序
    • 2. 最长公共前缀(AC80%)
  • 20190823 贝壳
    • 1. 吃糖果
    • 2. 距离最近的两个加油站的最大距离——二分
    • 3. 大整数截取
    • 4. 打怪物
  • 20190824 京东
    • 1. 消消乐
    • 2. 拼接迷宫
  • 20190825 快手
    • 3. 健身问题
    • 4. 求解一元一次方程

20190819 商汤

前两题都比较简单,没有记录,三四题为:

3. papers reading

【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第1张图片【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第2张图片

输入:
3
1001 -999 1002
输出
xtz

说明:三个数的得分一次为-1000, -997, -999,无论TZ如何取,都会取到-997,xtz赢。

输入:
4
1.1 2.2 3.3 4.4
输出:
TZ

说明:四个数得分依次为-0.387335, 1.89492,-0.336219,3.9878. TZ先取第4个,无论xtz如何取,TZ都可以取到第二个。

代码(AC60%):

#include 
#include 
#include 
#include 

using namespace std;

double oddScore(int i, vector<double>& nums)
{
	return i - nums[i - 1] - log(1 + exp(-nums[i - 1]));
}

double evenScore(int i, vector<double>& nums)
{
	return i - log(1 + exp(-nums[i - 1]));
}

pair<double, int> getScore(vector<double>& nums, int l, int r)
{
	double left_score = 0.0, right_score = 0.0, res_score = 0.0;
	bool select_left = true;
	if ((l % 2 == 0) && (r % 2 == 0))
	{
		left_score = evenScore(l, nums);
		right_score = evenScore(r, nums);
	}
	else if ((l % 2 == 1) && (r % 2 == 0))
	{
		left_score = oddScore(l, nums);
		right_score = evenScore(r, nums);
	}
	else if ((l % 2 == 0) && (r % 2 == 1))
	{
		left_score = evenScore(l, nums);
		right_score = oddScore(r, nums);
	}
	else
	{
		left_score = oddScore(l, nums);
		right_score = oddScore(r, nums);
	}
	res_score = left_score > right_score ? left_score : right_score;
	select_left = left_score > right_score ? true : false;
	pair<double, int> res{make_pair(res_score, select_left)};
	return res;
}

bool canWin(int N, vector<double>& nums)
{
	if (nums.size() == 2)
		return true;
	int l = 1, r = N;
	int TZ_flag = 1;
	double TZ_score = 0, xtz_score = 0;

	while (l < r)
	{
		pair<double, int> res = getScore(nums, l, r);

		if (TZ_flag)
			TZ_score += res.first;
		else
			xtz_score += res.first;
		if (res.second)
			l++;
		else
			r--;
		TZ_flag = 1 - TZ_flag;
	}
	double mid_score = 0.0;
	if (l % 2 == 0)
		mid_score = evenScore(l, nums);
	else
		mid_score = oddScore(l, nums);

	if (TZ_flag)
		TZ_score += mid_score;
	else
		xtz_score += mid_score;
	return TZ_score > xtz_score;
		
}

int main()
{
	//int N = 3;
	//vector nums{ 1001, -999, 1002 };
	int N = 4;
	vector<double> nums{ 1.1, 2.2, 3.3, 4.4 };
	bool TZ_win = canWin(N, nums);
	if (TZ_win)
		cout << "TZ" << endl;
	else
		cout << "xtz" << endl;

	system("pause");
	return 0;
}

4. 手动求导

【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第3张图片

【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第4张图片【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第5张图片

这题没写出来,下面贴上自己当时写的。

def g(a, b):
    return max(0, 1. - abs(a - b))

def g_gradient(a, b):
    if abs(a - b) <= 1:
        if a > b:
            return -1
        else:
            return 1
    else:
        return 0


def bilinear(F, H, W, y, x):
    F_y_x = 0.
    for h in range(H):
        for w in range(W):
            F_y_x += g(y, h) * g(x, w) * F[h][w]
    return F_y_x


def main(H, W, nums):
    F, P, Y, X = nums[:H], nums[H:H * 2], nums[2 * H: 3 * H], nums[3 * H:]
    Z = [[0 for _ in range(H)] for _ in range(W)]
    F_new = [[0 for _ in range(H)] for _ in range(W)]
    L = 0
    for h in range(H):
        for w in range(W):
            F_new[h][w] = bilinear(F, H, W, h + Y[h][w], w + X[h][w])
            Z[h][w] = P[h][w] * F_new[h][w]
            L += Z[h][w]

    loss = [[0 for _ in range(W)] for _ in range(H)]
    for h in range(H):
        for w in range(W):
            const = g(w + X[h][w], w) * F[h][w]
            if g_gradient(Y[h][w], h) == 0 or Z[h][w] == 0:
                loss[h][w] = 0
            else:
                loss[h][w] = L / Z[h][w] * P[h][w] * g_gradient(Y[h][w], h) * const
    return loss

H, W = 2, 2
nums = [[2., 2.],[0.33, -0.14],[0.21, -0.1],[-0.11, 0.0],[0.3, -0.49],[0.1, 0.4],[-0.1, -0.1],[0.49,-0.1],[0.45, -0.1]]
loss = main(H, W, nums)
for i in range(H):
    print(loss[i][0], loss[i][1])

20190822 美团

美团一共两个编程题。

1. 字符串排序

题目要求:将字符串的每个单词从z到a逆序排序,规定:
(1)空字符排在最前面
(2)短字符如果是长字符的前缀,短字符排在前面
(3)不能使用sort!

输入:(由“,”隔开的好多个单词拼接而成的字符串)
'waimai,dache,lvyou,liren,meishi,jiehun,lvyoujingdian,jiaopei,menpiao,jiudian'
输出:(排好序的字符串,将单词依旧用“,”隔开)
waimai,menpiao,meishi,lvyou,lvyoujingdian,liren,jiudian,jiehun,jiaopei,dache

我的想法(AC%):自定义排序函数compare。当时没意识到不能用sort,考完看讨论帖才发现。。

import functools
def func(s):
    ss = list(s.split(','))
    ss = sorted(ss, key=functools.cmp_to_key(compare))
    return ",".join(i for i in ss)

def compare(a, b):
    if not a or a == ' ' and b:
        return -1
    if not b or b == ' ' and a:
        return -1
    i = 0
    while i < min(len(a), len(b)):
        if a[i] > b[i]:
            return -1
        elif a[i] < b[i]:
            return 1
        i += 1
    if i == len(a):
        return -1
    if i == len(b):
        return 1
    return 0

s = 'waimai,dache,lvyou,liren,meishi,jiehun,lvyoujingdian,jiaopei,menpiao,jiudian'
print(func(s))

正确解法:快速排序或者归并排序,我写了一个快速排序:

def quicksort(s, start, end):
    if start < end:
        r = Partition(s, start, end)
        quicksort(s, start, r - 1)
        quicksort(s, r + 1, end)
    return s


def Partition(s, start, end):
    if start > end:
        return s
    pivot = s[start]
    j = start
    for i in range(start + 1, end):
        if compare(s[i], pivot):
            j += 1
            s[i], s[j] = s[j], s[i]
    s[j], s[start] = s[start], s[j]
    return j

def compare(a, b): # a < b, return True
    if not a:
        return True
    if not b:
        return False

    i = 0
    while i < min(len(a), len(b)):
        if a[i] < b[i]:
            return True
        elif a[i] > b[i]:
            return False
        i += 1
    return True if len(a) < len(b) else False


if __name__ == "__main__":
    s = 'waimai,dache,lvyou,liren,meishi,jiehun,lvyoujingdian,jiaopei,menpiao,jiudian'
    s = s.split(',')
    res = quicksort(s, 0, len(s))
    print(','.join(i for i in res[::-1]))  # 逆序

2. 最长公共前缀(AC80%)

题目要求:最大长度为十万的多个字符串,任意给两个字符串的编号,返回这两个字符串的最长公共前缀长度。

输入:
第一行输入一共一个整数n,代表字符串数量,最大为10000;
第2-n+1行,每行输入一个字符串,字符串长度最大为10万;
第n+2行开始,每行输入两个整数a和b,代表要求的字符串编号;

输出:
a和b对应的字符串的最长公共前缀长度。如果a或b不是有效字符串编号,则该行不输出结果。

输入:
4
abcdefg
acdef
acdfghijk
cdfg
1 2
2 3
3 4
输出:
1
3
0

这题其实思路是很简单的,但就只A了80%,后来反思的时候,发现应该是a和b的判断写的不对,应该在主函数的while循环中判断,而不应该在func函数中判断,当时A了80%,一直以为是超时或者超内存了,还跑去优化了半天,后来发现没啥必要。。。

正确解法(AC解法):【参考】

def func(s1, s2): # s1的长度更长
    res = 0
    for i in range(len(s2)):
        if s1[i] == s2[i]:
            res += 1
        else:
            break
    return res

n, ss = int(input()), []
for i in range(n):
    ss.append(input())
# ss = ['abcdefg', 'acdef', 'acdfghijk', 'cdfg']
while True:
    a, b = list(map(int, input().split()))
    s1, s2 = ss[a - 1], ss[b - 1]
    res = func(s1, s2) if len(s1) > len(s2) else func(s2, s1)
    print(res)

20190823 贝壳

四道编程题

1. 吃糖果

吃糖果问题,一共有n个糖果,第i个糖果的甜度为w_i,每次可以吃任意个糖,但是甜度必须是2的整数次方,问,最少吃几次,可以将所有糖果吃完?

第一行输入n,第二行输入n个糖果的甜度数组w_i。
输出一个整数,表示最少的次数。

输入:
5
1 1 2 3 3 
输出:
2

感觉很像leetcode279 Perfect Squares完全平方数那一题,但是照着这个代码写下来只能AC27%.

def func(nums):
    n = sum(nums)
    res = [float('inf')] * (n + 1)
    res[1] = 1
    for i in range(2, n + 1):
        j = 1
        while j * j <= i:
            if j * j == i:
                res[i] = 1
            else:
                res[i] = min(res[i], res[i - j * j] + 1)
            j += 1
    return res[-1]

n = int(input())
nums = list(map(int, input().split()))
print(func(nums))
nums = [1,1,2,3,3]
print(func(nums))

2. 距离最近的两个加油站的最大距离——二分

解法(对距离二分):这一题AC了。两个加油站的最小距离为1,最大距离为nums[-1](作为初始状态)
然后不断对距离进行二分求解。

def func(n, m, nums):
    left, right, res = 1, nums[-1], 0
    while left <= right:
        mid = (left + right) // 2
        if helper(nums, m, n, mid):
            res = mid
            left = mid + 1
        else:
            right = mid - 1
    return res

def helper(nums, m, n, mid):
    k, count = 0, 0
    for i in range(1, n):
        if nums[i] - nums[k] >= mid: #计算相邻加油站的最大距离
            count += 1
            k = i
    return count >= m - 1
n, m = input().split()
n, m = int(n), int(m)
nums = list(map(int, input().split()))
# n, m = 5, 3
# nums = [2,5,8,9,10]
print(func(n,m,nums))

3. 大整数截取

输入一个数字串,长度不超过30000,选择两个点l和r,截取数字串中的s[l, r]范围内的数字串,并且对1000000007取模,现在给定一个A_i,问有多少种截取方案,能够使得截取并取模之后的结果等于A_i。

第一行输入数字串
第二行输入一个整数T,表示有多少次查询
接下来T行,每行输入一个整数A_i,对于每个A_i,输出其方案数。

【输入】:
1000000008001
4 (问询的数量)
8
0
1
10
【输出】:
9
39
5
2

我的思路(暴力法):遍历所有的截取可能,使用字典记录每一种截取的结果值,存在字典d中,对于给定的A_i,直接return d[A_i]即可,超时,

def func(s):
    mo = 1000000007
    d = {}
    for i in range(len(s)):
        for j in range(i + 1, len(s)):
            cur_int = int(s[i:j]) % mo
            if cur_int not in d:
                d[cur_int] = []
            d[cur_int].append([i, j])
    return d

def ask(n, d):
    if n in d:
        return len(d[n])
    else:
        return 0

# s = input()
# d = func(s)
# t = int(input())
# for i in range(t):
#     print(ask(int(input()), d))
s = '1000000008001'
d = func(s)
print(ask(1, d))

优化思路(找规律):时间来不及,没考虑好,只有A_i等于0的情况,输出的结果是对的,这个需要考虑前导零,取模等情况。AC 27%。。。

def sum(n):
    return (1 + n) * n // 2

def func(n, s, cur_value):
    count = 0
    res = 0
    mo = 1000000007
    if cur_value == 0:
        for i in range(n):
            if s[i] == '0':
                count += 1
            else:
                res += sum(count)
                count = 0
        return res

    str_value = str(cur_value)
    for i in range(n):
        if s[i] == '0':
            count += 1
            continue
        if int(s[i:len(str_value) + i]) == cur_value:
            res = count + 1
            count = 0

        for j in range(i + 1, n):
            if int(s[i:j]) % mo == cur_value:
                res = count + 1
                count = 0
        count = 0
    return res

s = '1000000008001'
print(func(len(s), s, 1))

4. 打怪物

题目都没看。。

20190824 京东

两道编程题。吐槽一句,前面的选择题太恶心了。

1. 消消乐

二维消消乐,难点在于,不仅要消,格子还要往下掉。。。
【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第6张图片
【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第7张图片
类似于找连通块个数,据说只消掉最大的连通块,能AC55%。

2. 拼接迷宫

这题题目都没怎么看懂。
【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第8张图片
【笔试代码题记录】20190819-24 商汤/美团/贝壳/京东/快手_第9张图片

20190825 快手

3. 健身问题

一共有N个健身器材,第i个器材的位置距门口x_i米,每多走一米,健身效果加1,第i个器材的锻炼效果值为e[i],问,当使用1,2,…N种器材健身时,所能得到的最大健身效果是多少?(健身的过程就是:从门口出发,走到健身器材那儿锻炼,锻炼完后返回门口。)

输入dist数组,表示距离门口的远近
输入e数组,表示每种锻炼方式的效果值,这两个数组都是长度为N的。

输出N个整数,第k个整数表示使用k种健身器材锻炼所能取得的最大效果。

输入:
1 2 3 4 5
1 1 1 1 1
输出:
11 (对于使用一种健身器材的情况,选择第5个锻炼器材,考虑来回路程,共得到5+1+5=11的效果值)
12
13
14
15

思路(二维DP):自己写的,不知道能不能AC,但是测试用例是可以通过的。

def func(dists, e):
    n = len(dists)
    dp = [[0, 0] for _ in range(n + 1)]

    for i in range(n): # 初始化
        if 2 * dists[i] + e[i] > dp[1][0]:
            dp[1][0] = 2 * dists[i] + e[i]
            dp[1][1] = i

    for i in range(2, n + 1):
        for j in range(n):
            diff_dist = max(0, j - dp[i - 1][1])
            dp[i][1] = max(dp[i][1], j)
            dp[i][0] = max(dp[i][0], dp[i - 1][0] + e[j] + diff_dist)

            dp[i][1] = max(dp[i][1], dp[i - 1][1])
            dp[i][0] = max(dp[i][0], dp[i - 1][0] + e[j])
    return dp

dists = [1,2,3,4,5]
es = [1,1,1,1,1]

res = func(dists, es)
for i in range(len(dists)):
    print(res[i + 1][0])

4. 求解一元一次方程

输入一个字符串,假如 ‘2*X=6’,有解的话输出解,没有解的话输出-1.
这题的重点在于:eval函数的使用。real是实部,imag是虚部,

s = '2*X=6'

def solve(eq, var='X'):
    eqi = eq.replace('=', '-(') + ')' # 移项,将等号右边的移到左边去
    c = eval(eqi, {var: 1j})
    return -c.real / c.imag if c.imag else -1

print(int(solve(s)))

你可能感兴趣的:(笔试面试)