首页 > 编程语言 >初识算法 · 分治(3)

初识算法 · 分治(3)

时间:2024-11-22 11:50:43浏览次数:3  
标签:排序 nums int 分治 算法 初识 left 逆序

目录

前言:

归并排序

题目解析

算法原理

算法编写

求逆序对总数

题目解析

算法原理

算法编写


前言:

​本文的主题是分治,通过两道题目讲解,一道是归并排序,一道是求逆序对。
链接分别为:

912. 排序数组 - 力扣(LeetCode)

 LCR 170. 交易逆序对的总数 - 力扣(LeetCode)
题目分为三个部分讲解,一是题目解析,二是算法原理,三是算法编写,那么,话不多说,直接进行主题咯。


归并排序

题目解析

其实这个题目我们已经在分治1里面做过了,但是在分治1里面使用的是快排,本文介绍分治的另一种算法,即归并排序。

直接就进入原理吧!

算法原理

对于归并排序来说,基本思想是将数组不断的划分,不断的划分,直到划分到了一个数的情况,这么做的原因是为了后面方便合并数组,你想,如果存在两个有序数组,我们想要合并这个有序数组是不是十分容易?

一个双指针就可以搞定了。

那么对于归并算法同理,我们将数组不断的划分,不断的划分,直到划分为一个元素,此时,我们将该元素视为有序的,所以分治的第一步就完成了,我们应该递归回去了。回去之后,只需要完成一个操作就可以了,也就是合并有序数组。

那么对于归并排序来说,是将左右划分,并排好序,最后合并,这其实就是树的后序遍历:

对于快排来说,是先确定好了一个元素的位置,然后排序左右两边,这实际上是一种前序遍历:

现在直接算法编写吧!

算法编写

class Solution 
{
public:
    vector<int> tmp;
    void MergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return;
        //划分中间值
        int mid = (right + left) >> 1;
        MergeSort(nums, left, mid);
        MergeSort(nums, mid + 1, right);
        //开始合并数组
        int cur1 = left, cur2 = mid + 1, i = 0;
        while(cur1 <= mid && cur2 <= right)
            tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
        while(cur1 <= mid) tmp[i++] = nums[cur1++];
        while(cur2 <= right) tmp[i++] = nums[cur2++];
        //开始复原
        for(int i = left; i <= right; i++)
            nums[i] = tmp[i - left];
    }
    vector<int> sortArray(vector<int>& nums) 
    {
        tmp.resize(nums.size());
        MergeSort(nums, 0, nums.size() - 1);
        return nums;
    }
};

求逆序对总数

题目解析

在大一或者是大二的时候,多多少少都是学习过逆序对的,逆序对的概念就是前面的数字大于后面的数组,那么这两个数组成的数对,就成为逆序对。

那么题目是给我们一个数组,让我们求该数组里面的逆序对的个数。

算法原理

对于该题目,我们可以直接脑袋一空,直接就思考如何进行暴力解法,那多简单,是吧!

我们直接两个for循环,第一个For循环用来固定一个数,遍历其他数,判断是否满足逆序对的条件即可。该暴力解法的时间复杂度是O(N^2),在这道题目肯定是跑不过的,要不然也太对不起hard标签了。

所以,对于这道题目我们可以使用归并的思想,可能部分同学会觉得归并的思想和这道题并不搭边,我们不妨简单思考一下:

我们要求逆序对,那么该数组划分为两个区间之后,左边的逆序对 + 右边的逆序对,最后从左边选择数,再从右边选择数计算剩余的逆序对,三个逆序对的数一相加,我们就可以得到了总的逆序对个数。

但是但是,如果我们直接就是左边遍历右边遍历,那和第一种暴力解法也没有好到哪里去,所以从左边找和从右边找的时候,我们如果带上排序试试?

比如我们将左右两个数的逆序对找到了之后,顺便将这两个区间排序,那么,如果我们从左边找到一个数,从右边找一个数,如果左边的数字大于右边的数字,那么左区间的后面的数是不是都大于了后面的数字了?

这就爽了,我们直接就是+= mid - cur1 + 1就可以了。

那么排序我们排升序还是降序呢?

如果我们排序的是降序,遍历的过程,是极大有可能出现重复的:

此时这个策略就不可以了,现在的策略是找到有多少个数比他大。但是如果我们换一个策略呢?

找有多少个数比他小呢?

此时降序就十分吃香了。

所以降序和升序实际上都是可以的。

算法编写

int tmp[50010];
 public:
    int reversePairs(vector<int>& nums) 
    {
        return mergeSort(nums, 0, nums.size() - 1);
    }
    int mergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return 0;
        int ret = 0;
        int mid = (left + right) >> 1;
        ret += mergeSort(nums, left, mid);
        ret += mergeSort(nums, mid + 1, right);
        int cur1 = left, cur2 = mid + 1, i = 0;
        while(cur1 <= mid && cur2 <= right)
        {
            if(nums[cur1] <= nums[cur2])
            {
                tmp[i++] = nums[cur1++];
            }
            else
            {
                ret += mid - cur1 + 1;
                tmp[i++] = nums[cur2++];
            }
        }
        while(cur1 <= mid) tmp[i++] = nums[cur1++];
        while(cur2 <= right) tmp[i++] = nums[cur2++];
        for(int j = left; j <= right; j++)
            nums[j] = tmp[j - left];
        return ret;
    }

感谢阅读!​

标签:排序,nums,int,分治,算法,初识,left,逆序
From: https://blog.csdn.net/2301_79697943/article/details/143956151

相关文章

  • 【AI系统】Im2Col 算法
    作为早期的AI框架,Caffe中卷积的实现采用的是基于Im2Col的方法,至今仍是卷积重要的优化方法之一。从上一篇文章的介绍中可以看到,在CNN中卷积直接计算的定义中,卷积核在输入图片上滑动,对应位置的元素相乘后相加求和,滑窗的大小由卷积核决定。由于滑动操作时的窗口的数据横向是......
  • YOLOv8车牌识别系统 深度学习 LPRNet算法 pytorch 大数据 毕业设计(源码)✅
    YOLOv8车牌识别系统深度学习LPRNet算法pytorch大数据毕业设计(源码)✅1、项目介绍技术栈:Python3.8YOLOv8深度学习LPRNet算法pytorch2、项目界面(1)上传图片进行车牌识别(2)上传图片进行车牌识别2(3)多车牌号码进行车牌识别(4)上传视频进行车牌识别实时检测(5)连接......
  • 线段树分治
    线段树分治可以将“一段时间”的条件统筹处理。一种理解方法是考虑暴力,在每个时间点将当前状态调整出来,线段树分治做的事情相当于将一段时间内都有效的信息统一处理,当这个信息不再满足的时候就撤销。具体地,若一个条件(通常是可以用并查集维护的)在时间\([l,r]\)内有效,我们可以对......
  • 【模板】朱刘算法
    【模板】朱刘算法#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+2;introot,n,m;structEdge{ intu,v,w;}e[N];intid[N],vis[N],pre[N],incost[N];voidzhuliu(){ inttn=0; intres=0; while(1) { tn=0; for(inti=1;i<=n;i++){......
  • 【机器学习】解锁AI密码:神经网络算法详解与前沿探索
    ......
  • 初识C语言(上)
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、C语言是什么?二、初学之路1.编译器的选择2.我的第一个C语言程序3.main函数、printf和库函数1.main函数2.printf和库函数总结前言例如:为了参加职业技能大赛,学习单片机、Python、和Li......
  • 多目标优化算法:多目标伞蜥优化算法Multi-objective Frilled Lizard Optimization求解D
    一、伞蜥优化算法伞蜥优化算法(FrilledLizardOptimization,FLO)是2024年提出的一种新颖的元启发式算法,它模仿了伞蜥在其自然栖息地中独特的狩猎行为。该算法的核心原则被详细地描述并数学结构化为两个不同的阶段:(i)探索阶段,模仿蜥蜴对猎物的突然攻击;(ii)开发阶段,模拟蜥......
  • 代码随想录算法训练营day52 day53| 卡码网101.孤岛的总面积 102.沉没孤岛 103.水
    学习资料:https://www.programmercarl.com/kamacoder/0101.孤岛的总面积.html#思路邻接矩阵是否被遍历过;每个坐标点上的值为0、1、2等等;四个边的考虑;地图的遍历次数都是卡码网的题学习记录:101.孤岛的总面积点击查看代码#用深搜,遍历邻接矩阵的四个边,先遍历所有可遍历的岛屿,......
  • Python算法模版——并查集
        并查集常用于与图或树相关的算法题中,一个最为经典应用场景是求无向图的连通分量,为方便大家使用并查集算法,这里为大家提供一个Python的并查集算法模版,并加有详细注释。classUnionFind:def__init__(self,n):#n代表总共有n个节点,初始时每个节点以......
  • PID 控制算法 | 模糊控制 | 控制规则
    注:本文为几位功夫博主关于PID控制算法的几篇合辑。知识点交集未去重,如有内容异常请看原文。控制算法(一)——PID控制算法fxfreefly于2020-03-1717:25:43发布比例积分微分控制,简称PID控制,其中P表示比例、I表示积分、D表示微分。PID控制算法是最早发展起来......