数据结构算法每日一练(六)数组主元素

数据结构算法每日一练(六)数组主元素

难度: ⭐⭐⭐

题目: 已知一个整数序列 A = ( a 0 , a 1 . . . . . . a n − 1 ) A = (a_0,a_1......a_{n-1}) A=(a0a1......an1),其中 0 ≤ a i < n ( 0 ≤ i < n ) 0≤a_i<n(0≤i<n) 0ai<n(0i<n)

若存在 a p i = a p 2 = . . . . . . a p m = x 且 m > n / 2 ( 0 ≤ p k < n , 1 ≤ k ≤ m ) a_{pi}=a_{p2}= ......a_{pm}=x且m>n/2 (0≤p_k<n,1≤k≤m) api=ap2=......apm=xm>n/2(0pk<n,1km),则称x为A的主元素。

例如A=(0, 5, 5, 3, 5, 7, 5, 5),则5为主元素;又如A=(0, 5, 5, 3, 5, 1, 5, 7), 则A中没有主元素。假设A中的n个元素保存在一个一维数组中,请设计

一个尽可能高效的算法,找出A的主元素。若存在主元素,则输出该元素;否则输出-1.要求:

(1)给出算法的基本设计思想。

(2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。

(3)说明你所设计算法的时间复杂度和空间复杂度。

解法一

(1)算法思想: 构建一个大小为n的数组,用于对每个整数的计数,遍历一遍序列然后再遍历1次这个数组找到最大值,然后判断条件是否符合主元素条件。此解法易思考。 类似于桶排序,桶排序思想可参考👉桶排序

(2)

/**
 * 主元素算法
 * @param A 判定数组
 * @param n 数量n
 * @return
 */
int Majority(int A[], int n) {
    int i, *B; //定义B数组
    B = (int *)malloc(sizeof(int)*n); //分配空间
    memset(B, 0, sizeof(int)*n); //赋初值为0
    for (int i = 0; i < n; i++) {
        B[ A[i] ]++; //将A数组对应的值在B数组对应+1;
    }
    int max = 0;
    for (int j = 0; j < n; j++) { //遍历完查最大数量的数值
        if (B[j] > max) {
            max = B[j];
        }
    }
    if (max > n / 2)  //判断最多数量的数是否满足主元素的条件大于n/2
        return max;
    else
        return -1;

}

(3)时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n);

解法二(最优解法)

(1)算法思想: 策略是从前向后扫描数组元素,标记出一个可能成为主元素的元素Num。然后重新计数,确定Num是否是主元素。

算法可分为以下两步:

①选取候选的主元素。依次扫描所给数组中的每个整数,将第一个遇到的整数Num保存到c中,记录Num的出现次数为1; 若遇到的下一个整数仍等于Num,则计数加1,否则计数减1;当计数减到0时,将遇到的下一个整数保存到c中,计数重新记为1,开始新一轮计数,即从当前位置开始重复上述过程,直到扫描完全部数组元素。

②判断c中元素是否是真正的主元素。再次扫描该数组,统计C中元素出现的次数,若大于n/2,则为主元素;否则,序列中不存在主元素。

(2)

/**
 * 主元素算法
 * @param A 判定数组
 * @param n 数量n
 * @return
 */
int Majority1(int A[], int n) {
    int i , c, count = 1;
    c = A[0]; //设置A[0]为候选主元素
    for (int i = 1; i < n; i++) {
        if (A[i] == c) { //如果是候选主元素,则计数加一
            count++;
        }else {
            if (count > 0) { //如果不是候选主元素,计数减一
                count--;
            }else { //计数为0,更换候选主元素
                c = A[i];
                count = 1;
            }
        }
    }//for
    if (count > 0) { //统计候选主元素的次数
        for (int i = count = 0; i < n; i++) {
            if (A[i] == c) {
                count++;
            }
        }
    }//if
    if (count > n / 2)  //判断条件
        return c;
    else
        return -1;
}

(3)时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

解法三

(1)算法思想: 先对整个序列进行排序,然后遍历一遍看哪个元素最多,此算法也易想,相较于上述两种算法效率稍低。

(2)时间复杂度

若使用快速排序或者归并排序时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
冒泡排序获插入排序等时间复杂度为 O ( n 2 ) O(n^2) O(n2)
快速排序空间复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n),归并排序空间复杂度为 O ( n ) O(n) O(n)

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
一、 功能简介 本课件是一个动态演示数据结构算法执行过程的辅助教学软件, 它可适应读者对算法的输入数据和过程执行的控制方式的不同需求, 在计算机的屏幕上显示算法执行过程中数据的逻辑结构或存储结构的变化状况或递归算法执行过程中栈的变化状况。整个系统使用菜单驱动方式, 每个菜单包括若干菜单项。每个菜单项对应一个动作或一个子菜单。系统一直处于选择菜单项或执行动作状态, 直到选择了退出动作为止。 二、 系统内容 本系统内含84个算法,分属13部分内容,由主菜单显示,与《数据结构》教科书中自第2章至第11章中相对应。各部分演示算法如下: 1. 顺序表 (1)在顺序表中插入一个数据元素(ins_sqlist) (2)删除顺序表中一个数据元素(del_sqlist) (3)合并两个有序顺序表(merge_sqlist) 2. 链表 (1)创建一个单链表(Crt_LinkList) (2)在单链表中插入一个结点(Ins_LinkList) (3)删除单链表中的一个结点(Del_LinkList) (4)两个有序链表求并(Union) (5)归并两个有序链表(MergeList_L) (6)两个有序链表求交(ListIntersection_L) (7)两个有序链表求差(SubList_L) 3. 栈和队列 (1)计算阿克曼函数(AckMan) (2)栈的输出序列(Gen、Perform) (3)递归算法的演示  汉诺塔的算法(Hanoi)  解皇后问算法(Queen)  解迷宫的算法(Maze)  解背包问算法(Knap) (4)模拟银行(BankSimulation) (5)表达式求值(Exp_reduced) 4. 串的模式匹配 (1)古典算法(Index_BF) (2)求Next 函数值(Get_next)和按Next 函数值进行匹配 (Index_KMP(next)) (3)求 Next 修正值(Get_nextval)和按 Next 修正值进行匹配(Index_KMP(nextval)) 5. 稀疏矩阵 (1)矩阵转置 (Trans_Sparmat) (2)快速矩阵转置 (Fast_Transpos) (3)矩阵乘法 (Multiply_Sparmat) 6. 广义表 (1)求广义表的深度(Ls_Depth) (2)复制广义表(Ls_Copy) (3)创建广义表的存储结构(Crt_Lists) 7. 二叉树 (1)遍历二叉树  二叉树的线索化  先序遍历(Pre_order)  中序遍历(In_order)  后序遍历(Post_order) (2) 按先序建二叉树(CrtBT_PreOdr) (3) 线索二叉树  二叉树的线索化  生成先序线索(前驱或后继) (Pre_thre)  中序线索(前驱或后继) (In_thre)  后序线索(前驱或后继) (Post_thre)  遍历中序线索二叉树(Inorder_thlinked)  中序线索树的插入(ins_lchild_inthr)和删除(del_lchild_inthr)结点 (4)建赫夫曼树和求赫夫曼编码(HuffmanCoding) (5)森林转化成二叉树(Forest2BT) (6)二叉树转化成森林(BT2Forest) (7)按表达式建树(ExpTree)并求值(CalExpTreeByPostOrderTrav) 8. 图 (1)图的遍历  深度优先搜索(Travel_DFS)  广度优先搜索(Travel_BFS) (2)求有向图的强连通分量(Strong_comp) (3)有向无环图的两个算法  拓扑排序(Toposort)  关键路径(Critical_path) (4)求最小生成树  普里姆算法(Prim)  克鲁斯卡尔算法(Kruscal) (5)求关节点和重连通分量(Get_artical) (6)求最短路径  弗洛伊德算法(shortpath_Floyd)  迪杰斯特拉算法(shortpath_DIJ) 9. 存储管理 (1)边界标识法 (Boundary_tag_method) (2)伙伴系统 (Buddy_system) (3)紧缩无用单元 (Storage_compactio

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值