问题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() 函数)