【20190904】【校招笔试题】携程(待续)

问题1

思路及解答

# 方法一:因为相同种类必须分到同一组,所以必须要同一种类的分配完才能分配下一种,那么我们就需要记录每一种元素最后一次出现的位置
# 具体做法:记录每种元素最后一次出现的索引(用字典),然后对字符串进行遍历,如果索引到dic[某item],那么说明该元素已经输出完毕,此时输出该分组长度即可。
# strs = "aabbcddc"
strs = input()
dic = {}
for i, item in enumerate(strs):   # enumerate():枚举函数,枚举索引及其元素,多与for连用
    dic[item] = i
start, end = 0, 0   # 记录每个分组的开始和结束位置
result = []
for i, ch in enumerate(strs):
    end = max(end, dic[ch])   # 这个语句是关键!防止一个元素结束了,但其中有其他元素穿插,防止穿插在其中的元素没结束!见下面图分析!
    if i == end:
        result.append(end - start + 1)
        start = end + 1
print(",".join(map(str, result)))   # 将列表转换为字符串输出,用map(str, List)



# 方法二:这个题目有点类似于贪心算法中的区间调度问题,这里我统计了每种元素出现的区间,统计好的区间存在sections里,很容易想到它们是按照区间最左边的大小从小到大排列的,然后判断后一个区间和当前区间是否重叠,若不重叠则输出当前cnt+len(sections[i]值,否则cnt+=len(sections[i],因为涉及到索引溢出的问题,因此最后一个sections[-1]没有检查,最后再额外的进行检查即可。
# strs = "aabacc"
strs = input()
dic = {}
sections = []
def sections_judgement(sec1, sec2):   # 判断区间是否重叠,返回 'True' 则表示重叠
    min1, max2 = sec1[0], sec2[-1]
    return False if min1 > max2 else True
for i, item in enumerate(strs):
    if item not in dic:
        dic[item] = [i]
    else:
        dic[item].append(i)
for li in dic.values():
    sections.append(li)   # 因为上面for循环是从前往后,因此这些区间一定是由各元素起始位置递增排序的,所以下面只需要判断某区间和它之后的有没有相交即可
l = len(sections)   # 区间个数,其实是元素种类个数
cnt, result = 0, []
for i in range(l-1):
    if not sections_judgement(sections[i+1], sections[i]):
        result.append(cnt+len(sections[i]))
        cnt = 0
    else:
        cnt += len(sections[i])
for i in range(1, l-1):   # 统计前l-1个sections区间里的最大值,而不是取其长度之和,因为对于[1,2,3][2][4,5],只需要4>3即可,而不能用4>4判断!
    maximum = sections[i][-1] if sections[i][-1] > sections[i-1][-1] else sections[i-1][-1]
if sections[-1][0] > maximum:
    result.append(len(sections[-1]))
else:
    result[-1] += len(sections[-1])
print(result)
print(",".join(map(str, result)))   # 以字符串形式输出

 

end = max(end, dic[ch]) 分析:以 'aabbcddcd' 为例

  

问题2

 思路及解答

# 方法一:按第一种方法计算
N = int(input())
posi, neg = [], []
for _ in range(N):
    nums = list(map(float, input().split()))
    if nums[0] == 1:
        posi.append(nums[1])
    else:
        neg.append(nums[1])
l1, l2 = len(posi), len(neg)
cnt = 0
for i in range(l1):
    for j in range(l2):
        if posi[i] > neg[j]:
            cnt += 1
        elif posi[i] == neg[j]:   # 要考虑概率相同的情况!
            cnt += 0.5
print("{:.2f}".format(cnt / l1 / l2))



# 方法二:按第二种方式计算
def calAUC(prob, labels):
    f = list(zip(prob, labels))   # 将输入的参数,打包成一个元组,再转化成一个列表
    rank = [values2 for values1, values2 in sorted(f,key=lambda x:x[0])]
    rankList = []
    for i in range(len(rank)):
        if rank[i] == 1:
            rankList.append(i+1)
    pos_Num = 0
    neg_Num = 0
    for i in range(len(labels)):
        if labels[i] == 1:
            pos_Num += 1
        else:
            neg_Num += 1
    AUC = 0
    AUC = (sum(rankList) - (pos_Num*(pos_Num+1))/2) / (pos_Num*neg_Num)
    print(AUC)
    return AUC

n = int(input())
labels = []
prob = []
for i in range(n):
    a, b = list(map(float, input().split()))   # 输入两个的话,可以直接这种形式写!
    labels.append(a)
    prob.append(b)

calAUC(prob, labels)

问题3

思路及解答

知识点 

1. enumerate()的用法:同时枚举索引及元素。

2. AUC 的计算方法

(参考:AUC的计算方法

第一种:假设正样本个数是M,负样本个数是N,那么就有M*N个正负样本组合,统计这些组合里【正样本概率 > 负样本概率】的个数,记为cnt,那么AUC = cnt / (M*N)

第二种:将样本的预测概率从小到大排序,然后从1开始标序号,即rank值,然后将正样本的rank值相加(如果有出现概率相同的样本,取它们的rank平均值),再减M(M+1)/2,最后除以M*N。

3. zip() 函数的使用

(参考:Python3 zip() 函数

功能:将参数打包成元组,节省内存。

4. lambda 函数的使用 

例如:lambda x: x += 1,其中x是函数参数,x += 1 是函数体。

(参考: Python中lambda使用简单小结

5. sorted(iterable, cmp=None, key=None, reverse=False)

(参考:Python sorted() 函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Satisfying

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值