算法-找出N个数组的共同元素

一、代码与执行结果

财经新闻是大众了解金融事件的重要渠道,现有N位编辑,分别对K篇新闻进行专业的编辑与排版。需要您找出被这N位编辑共同编辑过的新闻,并根据这些新闻ID升序排列返回一个数组。

在这里插入图片描述

import random

# 查找编辑共同处理的新闻id
def find_common_news(N, K, news_ids):
    # 使用集合的交集操作找出被所有编辑共同编辑过的新闻
    common_news_set = set(news_ids[0]) # 时间 O(k)   # 空间 O(N)
    for i in range(1, N):  # O(N*K)
        common_news_set.intersection_update(news_ids[i]) 
    # 返回升序排列的结果
    return sorted(list(common_news_set)) # O(M * log(M)) 排序算法是 Timsort
    #  O(N * K + M * log(M))

# 生成模拟数据, 作为find_common_news的输入
def generate_random_lists(m=8, N=10, K=60):
    # 第1步:生成这些编辑们处理的新闻中一定重复的新闻id
    lists = random.sample(range(1, K+1), m)
    print('期望输出: ',sorted(lists)) 
    
    # 第2步:生成编辑们分别处理的新闻个数
    lsts2 = [random.randint(1, K) for _ in range(N)]
    # print(lsts2)

    # 第3步:生成这8个编辑各自处理的新闻中可能不重复的新闻id
    result = []
    for num in lsts2:
        rand_nums = [random.randint(1, K) for _ in range(num)]
        result.append(rand_nums)
    # print(result) 

    # 第4步:将可能不重复部分列表与重复列表合并, 得到每个编辑处理的新闻id列表模拟数据
    merged_result = []
    for sublist in result:
        # 注意:可能不重复部分列表 
        merged_list = list(set(sublist + lists))
        random.shuffle(merged_list) # 防止自动排序, 打乱处理
        merged_result.append(merged_list)
    return merged_result # 输出10个编辑分别处理的新闻id


if __name__ == "__main__":
    # 构造数据
    m, N, K = 8, 10, 60 # m为编辑们共同处理的新闻个数
    merged_result = generate_random_lists(m, N, K) # 生成编辑们各自处理的新闻id列表
    print('输入: ', merged_result)
    print("实际输出: ",find_common_news(N, K, merged_result))

输出:

期望输出:  [3, 16, 17, 22, 31, 32, 34, 52]
输入:  [[3, 40, 34, 22, 52, 14, 35, 31, 27, 32, 16, 17], [32, 8, 9, 3, 52, 36, 33, 44, 60, 12, 19, 17, 34, 43, 2, 10, 50, 45, 14, 42, 22, 41, 51, 55, 27, 11, 16, 39, 35, 15, 59, 49, 47, 28, 1, 26, 4, 31], [17, 33, 12, 24, 52, 47, 32, 23, 58, 27, 1, 16, 31, 18, 42, 60, 28, 19, 15, 3, 20, 53, 49, 57, 25, 21, 26, 9, 56, 35, 14, 4, 22, 5, 10, 13, 34, 8, 41], [40, 51, 21, 36, 34, 10, 52, 31, 57, 26, 41, 3, 32, 12, 9, 56, 39, 7, 59, 13, 17, 53, 22, 4, 27, 42, 16, 25], [35, 31, 27, 22, 39, 40, 11, 58, 30, 16, 56, 47, 17, 26, 34, 12, 53, 5, 3, 45, 1, 8, 32, 18, 52, 6], [9, 40, 26, 36, 39, 35, 54, 34, 17, 46, 43, 13, 52, 56, 37, 14, 45, 22, 6, 41, 25, 49, 20, 5, 7, 3, 31, 44, 50, 4, 30, 32, 16, 1], [2, 33, 32, 3, 8, 43, 31, 58, 42, 17, 1, 16, 52, 30, 59, 6, 34, 13, 29, 46, 51, 12, 22], [57, 31, 16, 14, 32, 9, 20, 18, 24, 30, 4, 17, 22, 27, 43, 12, 37, 2, 13, 59, 34, 53, 3, 48, 21, 55, 52, 25], [24, 3, 34, 31, 56, 19, 12, 8, 16, 52, 51, 10, 22, 32, 49, 33, 17, 2, 48, 15, 45, 42, 25, 60, 30, 46, 47, 36, 39, 58, 6, 20, 5, 37, 14], [17, 22, 58, 32, 52, 13, 5, 26, 34, 48, 3, 31, 27, 24, 2, 16]]
实际输出:  [3, 16, 17, 22, 31, 32, 34, 52]

二、函数关键信息

函数名称:find_common_news
参数N: 整数,表示编辑的数量。
参数K: 整数,表示新闻的总数。
news_ids: 一个包含N个列表的列表,每个列表包含一个编辑编辑过的新闻编号。
返回值:一个升序排列的列表,包含所有编辑共同编辑过的新闻编号。

三、程序设计原理

1、初始化一个空集合common_news_set,用于存储所有编辑共同编辑过的新闻编号。
2、将第一个编辑编辑过的新闻编号集合作为初始集合,存储到common_news_set中。
3、遍历第2到第N个编辑的新闻编号集合:
3.1、使用集合的intersection_update方法,将当前编辑的新闻编号集合与common_news_set取交集,并更新common_news_set。
3.2、这样,common_news_set中将保留与当前编辑共同编辑过的新闻编号,即找到所有编辑共同编辑过的新闻编号的交集。
4、将common_news_set转换为列表,并使用Python的sorted函数对列表进行升序排序。
5、返回排序后的列表作为结果。

四、复杂度分析

1、时间复杂度分析
1.1、使用集合的交集操作找出被所有编辑共同编辑过的新闻:遍历每个新闻集合进行交集操作,时间复杂度为O(K),其中K为所有编辑操作的总数。
1.2、排序:对交集结果进行排序,时间复杂度为O(NlogN),其中N为符合条件的新闻数量。
1.3、综合来看,时间复杂度为O(K + NlogN)。
2、空间复杂度分析
common_news_set集合:存储被所有编辑共同编辑过的新闻,最坏情况下需要存储所有新闻,空间复杂度为O(N)。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 首先要确定i和j的位置,如果i和j相邻,则直接返回A[i/2](i/2即为i和j的父节点);如果i和j不相邻,则令i1=i,j1=j,然后按照以下步骤循环:1. 如果i1和j1的奇偶不同,则令i1=i1/2,j1=j1/2;2. 如果i1和j1的奇偶相同,则令i1=i1/2,j1=(j1-1)/2(j1-1是为了保证j1的父节点是i1的父节点的兄弟节点)3. 如果i1=j1,则返回A[i1]4. 如果i1和j1的值不相等,则重复以上步骤,直到i1=j1C语言实现如下:int FindCommonAncestor(int A[], int i, int j) { int i1=i, j1=j; while(i1!=j1) { if(i1%2 != j1%2) { i1 = i1/2; j1 = j1/2; } else { i1 = i1/2; j1 = (j1-1)/2; } } return A[i1]; } ### 回答2: 要求找出数组元素A[i]和A[j]的最近的共同祖先,首先需要确定完全二叉树的性质。在一棵顺序存储的完全二叉树中,二叉树的节点按层序依次存储在数组中。假设数组的长度为N,则根节点为A[0],节点A[i]的左子节点为A[2*i+1],右子节点为A[2*i+2]。 为了简化问题,先找到节点A[i]和A[j]的公共祖先,然后进一步判断其最近的公共祖先。具体算法如下: 1. 对于节点A[i]和A[j],比较它们的下标大小,假设i < j。 2. 若j为i的父节点或者是i的右子节点,说明i就是j的祖先,返回A[i]即可;反之,进入步骤3。 3. j除以2,得到上一层的父节点的下标p,若p小于i,则继续步骤4;反之,进入步骤5。 4. 将p赋值给j,重复步骤2;否则,进入步骤5。 5. 返回A[p]作为A[i]和A[j]的最近的公共祖先。 以下是相应的C语言代码实现: ```c #include <stdio.h> int findCommonAncestor(int A[], int i, int j) { if (i == j) { return A[i]; } if (i > j) { int temp = i; i = j; j = temp; } while (j > i && j % 2 != 0) { j = (j - 1) / 2; } return A[j / 2]; } int main() { int A[] = {1, 2, 3, 4, 5, 6, 7}; int i = 1; int j = 3; int commonAncestor = findCommonAncestor(A, i, j); printf("数组元素A[%d]和A[%d]的最近的共同祖先为:%d\n", i, j, commonAncestor); return 0; } ``` 以上代码中的示例数组A为{1, 2, 3, 4, 5, 6, 7},假设要找的节点为A[1]和A[3],则返回的最近的共同祖先为1。 ### 回答3: 思路: 1. 确定数组元素A[i]和A[j]在二叉树中的位置,计算它们的层次差。 2. 在保持A[i]和A[j]层数相等的前提下,不断将它们上移至祖先节点,直到到达共同祖先。 算法实现: ```c #include <stdio.h> // 计算元素数组中的层次 int getLevel(int n, int index) { if (index < 0 || index >= n) return -1; int level = 0; while ((1 << level) - 1 <= index) { level++; } return level - 1; } // 获取共同祖先 int getCommonAncestor(int n, int A[], int i, int j) { if (i < 0 || i >= n || j < 0 || j >= n) return -1; int level_i = getLevel(n, i); int level_j = getLevel(n, j); // 保持i和j层数相等 while (level_i > level_j) { i = (i - 1) / 2; level_i--; } while (level_j > level_i) { j = (j - 1) / 2; level_j--; } // 不断上移找到共同祖先 while (i != j) { i = (i - 1) / 2; j = (j - 1) / 2; } return A[i]; } int main() { int N = 10; // 数组元素个数 int A[N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 示例数组 int i = 0; // 元素i的索引 int j = 2; // 元素j的索引 int commonAncestor = getCommonAncestor(N, A, i, j); printf("元素A[%d]和A[%d]的最近共同祖先是:%d\n", i, j, commonAncestor); return 0; } ``` 以上是一个简单的算法实现,通过计算元素的层次差,并不断上移找到共同祖先节点。需要注意数组索引是否越界的情况,以及输入参数的有效性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

高山莫衣

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

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

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

打赏作者

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

抵扣说明:

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

余额充值