算法-分治和逆序

news2024/11/18 1:41:14

分治法(Divide and Conquer)是一种重要的算法设计范式,它通过将复杂的问题分解成更小、更易于管理和解决的子问题,然后递归地解决这些子问题,最后将子问题的解合并以得到原问题的解。分治法通常用于排序、搜索、数学计算和优化等问题。

分治法的核心思想可以概括为三个步骤:

  1. 分解(Divide):将原问题分解为若干个规模较小的相同问题。

  2. 解决(Conquer):递归地解决这些子问题。如果子问题足够小,可以直接解决。

  3. 合并(Combine):将子问题的解合并以得到原问题的解。

时间复杂度
  1. 最佳情况:如果每次分区操作都能将数组均匀地分成两个相等的部分,那么快速排序的时间复杂度是最优的。在这种情况下,递归的深度是 logn(其中 n 是数组的长度),每一层的工作时间是 O(n)。因此,总的时间复杂度是 �(�log⁡�)O(nlogn)。

  2. 平均情况:在大多数情况下,快速排序的性能接近最佳情况,尽管可能不是完全均匀的划分。平均情况下的时间复杂度也是 O(nlogn)。

  3. 最坏情况:如果每次分区操作都极不均匀,例如每次只将数组分成一个元素和其余元素两部分,那么递归的深度将是 �n,每一层的工作时间仍然是 �(�)O(n),但总共有 �n 层。因此,总的时间复杂度是 O(n的平方)。这种情况通常发生在数组已经有序或者完全逆序的情况下。

逆序

2 4 1 3 5

初始化逆序数 count=0;

(2,4)正序

(2,1)逆序,count=1;

(2,3)正序

(2,5)正序

(4,1)逆序,count=2;

(4,3)逆序,count=3;

(1,3)正序

(1,5)正序

(3,5)正序

一般来讲一个一个对照的话,一般就是也就是说这种算法的时间复杂度上限为O(n2)。

但是分治策略,可以降低到nlogn 因此可以直接操作。

对应算法

两个有序的序列 去合并成新序列,并且找到逆序数。

假定分解后的两个序列分别为A,B,(A在前,B在后)已得到A,B的逆序数分别为rA,rB且假定计数完逆序数后把A,B排序为有序序列,以此为基础,得到A,B两序列元素之间的逆序数的合并算法为MAC算法(有(ai,bj)组合,ai来自A,bj来自B,如果有逆序就要计数)。

算法 MAC. 给定两个有序序列A、B,输出它们之间的逆序数和一个合并后有序 的序列C。

MAC1. [初始化变量] 初始化A、B、C的下标i=0,j=0,k=0,和计数值               count=0,初始化C为空序列;

MAC2. [A或B是否没有元素?]if A没有元素 or B没有元素,把有元素 不空的那个序列剩余的元素全部加到C的后面并返回count和C;

MAC3. [是否要增加逆序数?] If A[i]>B[j],count增加的计数值为A中还              有的元素数量,把B[j]从B中移到C的最后面,j←j+1,k←k+1;

MAC4. [无需增加逆序数] 把A[i]从A中移到C的最后面,                         i←i+1,k←k+1,回到MAC2。停止的条件就是有一方数组为空 停止全部操作加入到第三个序列
给个例子

例2.2 用MAC算法数一下序列A= {2,4 ,7},B={1,3,5,8}之间的逆序数。

初始化逆序数 i=0,j=0,k=0,count=0,C={};

A[i]>B[j],count=3,A={2,4,7},B={3,5,8},C={1},j=1,k=1;
A[i]<B[j],count=3,A={4,7},B={3,5,8},C={1,2},i=1,k=2;
A[i]>B[j],count=5,A={4,7},B={5,8}C={1,2,3},j=2,k=3;
A[i]<B[j],count=5,A={7},B={5,8}C={1,2,3,4},i=2,k=4;
A[i]>B[j],count=6,A={7},B={8}C={1,2,3,4,5},j=3,k=5;
A[i]<B[j],count=6,A={},B={8}C={1,2,3,4,5,7},i=3,k=6;
C={1,2,3,4,5,7,8},k=7,返回count,C;

最后计数值count=6,C={1,2,3,4,5,7,8}。

但我越来越感觉其实这个需要分治策略时候刚好是分成了两个有序数列。因为只有这样才是所谓mac算法的前提。这样不仅能够求出逆序数,同样的可以使得序列按照顺序排列。

SAC算法

递归算法和分治策略

将一个序列排序并且找到全部逆向序列数

算法 SAC. 给定序列S,输出该序列的的逆序数count和排序后的S

SAC1. [是否分解到基问题?] if S的元素只有1个,count=0,返回count              和S;

SAC2. [分解S]把S分解为两个序列A,B,A是前半,B是后半;

SAC3. [递归] 分别对A、B递归执行SAC算法,即(rA,A)=SAC(A);

              (rB,B)=SAC(B);

SAC4. [合并] 把对A,B执行MAC合并算法,即(r,S)=MAC(A,B);  SAC5. [加总] count←r+rA+rB,返回count,S。
java
package org.com.test;
import java.io.*;
import java.util.*;

public class SAC {
    public static void main(String[] args) {
        System.out.println("请输入待计数逆序的整数序列(以空格分开,各项值都不同)");
        Scanner in = new Scanner(System.in);
        String line = in.nextLine();
        String[] tokens = line.split(" ");
        int[] S1 = new int[tokens.length];
        for (int i = 0; i < tokens.length; i++) {
            S1[i] = Integer.parseInt(tokens[i]);
        }
        int count = sortAndCount(S1);
        for (int i = 0; i < S1.length; i++) {
            System.out.print(S1[i] + " ");
        }
        System.out.print("\n逆序计数为: " + count);
    }

    private static int sortAndCount(int[] S) {
        if (S.length == 1)
            return 0;
        int n = S.length / 2;
        int[] A = new int[n];
        int[] B = new int[S.length - n];
        int j = 0;
        for (int i = 0; i < A.length; i++)
            A[i] = S[j++];
        for (int i = 0; i < B.length; i++)
            B[i] = S[j++];
        int rA = sortAndCount(A);
        int rB = sortAndCount(B);
        int r = mergeAndCount(A, B, S);
        return (r + rA + rB);
    }

    private static int mergeAndCount(int[] A, int[] B, int[] C) {
        int i = 0, j = 0, k = 0, count = 0;
        for (int e: A)
            System.out.print(e);
        System.out.println();
        for (int e: B)
            System.out.print(e);

        while (i < A.length && j < B.length) {
            if (A[i] > B[j]) {
                count += A.length - i;
                C[k++] = B[j++];
            } else {
                C[k++] = A[i++];
            }
        }
        if (i == A.length && j < B.length)
            for (int l = j; l < B.length; l++)
                C[k++] = B[l];
        if (i < A.length && j == B.length)
            for (int l = i; l < A.length; l++)
                C[k++] = A[l];
        return count;
    }
}
python
# @Author: K1t0
# @Time: 2024/9/19
# @Description: 分治算法 逆序数

# 函数功能: SAC 算法
def SAC(list2):
    # 递归结束判定条件
    if len(list2) <= 1:
        return 0
    # 分组序列 A ,B Num_A Num_B
    A=[];B=[]
    Num_A=len(list2)//2
    Num_B=len(list2)-Num_A
    for i in range(len(list2)):
        if i<Num_A:
            A.append(list2[i])
        else:
            B.append(list2[i])
    rA=SAC(A)
    rB=SAC(B)
    r=MAC(A,B,list2)
    return r+rA+rB
# 函数功能:MAC 算法
def MAC(A,B,C):
    # A B C 下标
    i=0;j=0;k=0;count=0
    # A B 逆序判定
    while i<len(A) and j <len(B):
        if A[i]>B[j]:
            count+=len(A)-i
            C[k]=B[j]
            j+=1;k+=1
        else:
            C[k]=(A[i])
            i+=1;k+=1
    # 任何一方 结束,另一方全部加入C的序列中
    if i==len(A) and j<len(B):
        for c in range(j,len(B)):
            C[k]=B[c]
            k+=1
    if i<len(A) and j==len(B):
        for c in range(i,len(A)):
            C[k]=A[c]
            k+=1

    return count


if __name__=="__main__":
    # 接收序列
    list1=input("Input your list:").split()
    list2=[int(num) for num in list1 ]
    print(SAC(list2))
    print(list2)
一些理解

首先分治算法非常的简单,但是在写代码的时候总是会出现问题,首先就是因为这个参数传递的问题,因为java参数传递是引用传递,但是python传递是通过可变类型传递,因此我们需要传递一个参数进去才能达到引用的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2170411.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos怎么执行脚本

方法一&#xff1a;切换到shell脚本所在的目录&#xff08;此时&#xff0c;称为工作目录&#xff09;执行shell脚本 cd /data/shell ./hello.sh 方法二&#xff1a;以绝对路径的方式去执行bash shell脚本 /data/shell/hello.sh 方法三&#xff1a;直接使用bash 或sh 来执行…

消费类摄像头热销海内外,萤石出货量全球排名第一

随着消费者对家庭安全、便捷生活的需求日益增长&#xff0c;智能摄像头作为智能家居的重要组成部分&#xff0c;其市场需求将持续扩大。 IDC《全球智能家居设备市场季度跟踪报告&#xff0c;2024年第二季度》显示&#xff0c;二季度全球智能摄像头市场&#xff08;包含消费级室…

足球预测模型理论:足球数据分析——XGBoost算法实战

简介&#xff1a;本文将探讨如何使用XGBoost算法进行足球数据分析&#xff0c;特别是足球运动员身价估计。我们将通过实例和生动的语言&#xff0c;解释XGBoost算法的原理和实际应用&#xff0c;帮助读者理解复杂的技术概念&#xff0c;并提供可操作的建议和解决问题的方法。 足…

ML 系列:机器学习和深度学习的深层次总结(04)多元线性回归 (MLR)

图 1.多元线性回归与简单线性回归 一、说明 线性回归从一维推广到多维&#xff0c;这与单变量线性回归有很多不同&#xff0c;情况更加复杂&#xff0c;而在梯度优化也需要改成向量梯度&#xff0c;同时&#xff0c;数据预处理也成了必要步骤。 二、综述 多元线性回归是简单线性…

基于flask常见trick——unicode进制编码绕过

前言 Flask 是一个轻量级的 Python Web 框架&#xff0c;设计上追求简洁和灵活性&#xff0c;适合构建中小型的 Web 应用程序。 其出题方便&#xff0c;经常能在CTF比赛中见到&#xff0c;常见题型有debug模式算pin码、ssti、原型链污染等&#xff0c;其中后两者属于通用漏洞…

IPLOOK百万级用户容量核心网惊艳亮相北京PT展

2024年9月25日&#xff0c;以“推动数实深度融合&#xff0c;共筑新质生产力”为主题&#xff0c;本届中国国际信息通信展&#xff08;PT展&#xff09;在北京国家会议中心正式拉开帷幕。 广州爱浦路网络技术有限公司&#xff08;简称&#xff1a;IPLOOK&#xff09;&#xff…

SocialAI:拉满情绪价值的社交情感依托平台

​近日&#xff0c;SocialAI这款人工智能社交应用在苹果商店上线仅三天便引发广泛关注。它以独特的功能和创新的社交体验迅速走红&#xff0c;为社交领域带来了新的变革。 其亮点包括注册送百万虚拟粉丝&#xff0c;皆AI 生成回复和点赞&#xff0c;用户可自由定制关注者类型&…

鸿蒙开发(NEXT/API 12)【硬件(外设扩展驱动客户端开发)】驱动开发服务

Driver Development Kit&#xff08;驱动开发套件&#xff09;为外设驱动开发者提供高效、安全、丰富的外设扩展驱动开发解决方案C-API&#xff0c;支持外设驱动开发者为消费者带来外设即插即用的极致体验。 支持开发者开发外设配件的高阶功能&#xff0c;满足消费者高阶使用场…

erlang学习:Linux命令学习6

for循环学习 打印九九乘法表 for i in {1..9};do %%取1-9for j in $(seq 1 $i);do %%取1-iecho -n "$j*$i$((i*j)) " %%进行九九乘法表打印doneecho done尝试了很多次报错是因为后面的换行符不对&#xff0c;window系统中的换行符与linux对不上&#xff0c;因…

three.js----快速上手,如何用vue在web页面中导入 gltf/glb , fbx , obj 模型

首先去three.js官网下载three.js包,或者在直接在vue项目中 npm install three0.158.0 --save (学three.js需要有一点前端基础,基础掌握不牢的还是从基础开始) 这个0.158.0是版本号,不用纠结选新的还是选旧的,新手先不考虑这些,three.js基本上个把月就会更新一次,选一个不太新…

【CSS】字体文本

color 颜色font-size 大小font-family 字体font-style 样式font-weight 加粗text-decoration 下划线text-shadow 阴影text-transform 大小写变换text-indent 缩进text-align 水平对齐 、vertical-align垂直对齐text-overflow 溢出word-wrap 换行word-break 截断white-space 空白…

Uptime Kuma运维监控服务本地部署结合内网穿透实现远程在线监控

目录 前言 主要功能 一、前期准备 本教程环境为&#xff1a;Centos7&#xff0c;可以跑Docker的系统都可以使用本教程安装。 本教程使用Docker部署服务&#xff0c;如何安装Docker详见&#xff1a; 二、Docker部署Uptime Kuma 三、实现公网查看网站监控 四、使用固定公…

一文看懂英伟达系列显卡特点及性能参数对比

英伟达介绍 英伟达(NVIDIA)是美国一家专业的计算机图形芯片制造商&#xff0c;作为全球领先的GPU生产商&#xff0c;英伟达显卡产品系列涵盖GeForce、Quadro、Tesla、NVS、GRID等消费级、专业级和企业级市场。并被广泛应用于游戏、深度学习、科学计算和图形处理等领域。 NVID…

建筑智能,推动智慧社区发展

建筑智能已经成为现代城市建设的热门词汇。它不仅是提高城市建筑现代化水平的必由之路&#xff0c;也是未来城市智能化的重要标志。其中&#xff0c;智能社区是建筑智能化的重要环节之一。 智能社区是指以信息技术为基础&#xff0c;通过信息技术实现社区设施设备网络化、监管…

JS设计模式之模板方法模式:打破束缚,解密代码复用的精髓

一. 前言 在前端开发中&#xff0c;模板方法模式是一种常用的设计模式&#xff0c;它能够有效地提高代码的复用性和扩展性。在 JavaScript 中&#xff0c;模板方法模式的应用广泛&#xff0c;常被用于组件的生命周期管理、请求封装和拦截器设计、表单验证等多个场景。 本篇文…

数据结构和算法之树形结构(3)

文章出处&#xff1a;数据结构和算法之树形结构(3) 关注码农爱刷题&#xff0c;看更多技术文章&#xff01;&#xff01; 四、平衡二叉树(接前篇) 上一章节讲到为了避免二叉查找树退化成链表后的极度不平衡带来的低效率而衍生出了平衡二叉树&#xff0c;平衡二叉树的严格定义…

CDGA|数据治理:策略与价值的深度融合

在当今这个数据驱动的时代&#xff0c;企业数据治理的重要性日益凸显。数据不仅是企业的核心资产&#xff0c;更是驱动业务决策、优化运营流程、创新产品服务的关键力量。然而&#xff0c;要让数据治理真正发挥价值&#xff0c;企业需要采取一系列策略来确保数据的准确性、完整…

Unity 资源 之 PoseAI 基于肌肉的姿势创作工具

Unity 资源 之 PoseAI 基于肌肉的姿势创作工具 一&#xff0c;前言二&#xff0c;资源包内容三&#xff0c;免费获取资源包 一&#xff0c;前言 Unity 开发者们&#xff0c;今天要为大家介绍一款极具创新性的工具 ——PoseAI。 PoseAI 是一种最先进的基于肌肉的姿势创作工具&…

Flink基本概念和算子使用

基础概念 Flink是一个框架和分布式处理引擎&#xff0c;用于对无界数据流和有界数据流进行有状态计算&#xff0c;它的核心目标是“数据流上的有状态计算”。 有界流和无界流 有界流&#xff1a;具有明确的开始和结束时间&#xff0c;数据量有限。适合使用批处理技术&#xf…

Elasticsearch实战宝典:从日志分析到实时数据监控,全方位解锁搜索与分析的无限可能!

Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;常用于处理大规模数据。它提供了强大的全文搜索、结构化搜索、实时统计分析等功能。以下是一些 Elasticsearch 的实战应用案例。 1. 日志分析系统 Elasticsearch 经常被用于集中式日志管理&#xff08;Centralized…