当前位置: 首页 > news >正文

算法专题七: 分治归并

目录

  • 1. 排序数组
  • 2. 交易逆序对的总数
  • 3. 计算右侧小于当前元素的个数
  • 4. 翻转对

1. 排序数组

在这里插入图片描述
在这里插入图片描述

算法思路: 本道题使用归并的思路进行排序, 先讲数组分为左右两个区间, 然后合并两个有序数组.

class Solution {vector<int> tmp;
public:vector<int> sortArray(vector<int>& nums) {tmp.reserve(nums.size());mergesort(nums,0,nums.size()-1);return nums;}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];}}
};

2. 交易逆序对的总数

在这里插入图片描述

算法思路:

在这里插入图片描述

先找左半部分的逆序对, 然后再找右半部分的逆序对, 最后再一左一右的找逆序对, 找完左半部分和右半部分之后给数组排个序对数组的结果不影响, 而且排完序之后找一左一右的逆序对还简单些, 不由得我们就可以想到此方法和归并排序的思路一样, 只不过再排序的过程中增加了统计逆序对的个数. 这里可以采用两种策略, 第一种固定当前位置的值, 然后找前面有多少数是比我大的, 第二种策略, 固定当前位置的值, 找后面有多少元素是比我小的.

  • 首先使用第一种策略, 固定一个数, 在前面找比我大的元素的个数.

在这里插入图片描述
当前为升序的排序, 我们归并的时候如果nums[cur1] <= nums[cur2] 时, 此时我们只需要把cur1++就行, 如果nums[cur1]在某一个位置大于nums[cur2]时,此时已经找到了比nums[cur2]大的元素, 那么mid- cur1 + 1这段区间里面的所有值都比nums[cur2]大, 此时统计逆序对的数量即可, 然后再让cur2++, 但是不要往了我们还要排序, 所以这一步写在归并数组那里即可.
那么既然升序可以, 降序可不可以呢?

在这里插入图片描述
如图所示, 该数组为降序的时候, 固定cur1, cur2位置时,如果cur1大于cur2则开始统计cur1中大于cur2元素的个数, 看似没有什么问题, 但是如果进入下一次循环中, cur1++之后还有可能大于cur2,此时在统计那不是重复了嘛, 显然结果是错误的

  • 第二种策略: 固定一个数, 然后找后面比我小的元素的个数

在这里插入图片描述
首先先来看降序的数组, 来统计固定一个位置之后, 后面有多少元素比我小, 当nums[cur1] <= nums[cur2]时, 此时不是我们想要的结果, 我们需要的是nums[cur1]>nums[cur2], 这个时候, 我们统计后面有多少个元素比我小即可, 很显然此时数组是降序的, 所以right - cur2 + 1 即为结果

if(nums[cur1] <= nums[cur2])
tmp[i++] = nums[cur2++];
else
{
ret += right - cur2 + 1;
tmp[i++] = nums[cur1++];
}

反之我们来看一下升序

在这里插入图片描述

此时数组为升序, 我们需要找后面比前面小的元素的个数, 当固定到cur1之后, nums[cur1] > nums[cur2]时, 此时开始找结果, 在后面看在mid到cur2之间的这部分都是比nums[cur1]小的, 但是下一次cur2++之后还有可能是小于nums[cur1]的, 所以此时重复统计了 , 结果是错误的.

代码部分:

策略1

class Solution {int tmp[50000];
public:int reversePairs(vector<int>& record) {return mergeSort(record,0,record.size()-1);}int mergeSort(vector<int>& nums,int left,int right){if(left>=right) return 0;int ret = 0;int mid = (right + left) >> 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 i = left; i <= right; i++){nums[i] = tmp[i - left];}return ret;}
};

策略2

class Solution {int tmp[50000];
public:int reversePairs(vector<int>& record) {return mergeSort(record,0,record.size()-1);}int mergeSort(vector<int>& nums,int left,int right){if(left>=right) return 0;int ret = 0;int mid = (right + left) >> 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[cur2++];else{ret += right - cur2 + 1;tmp[i++] = nums[cur1++]; }}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];}return ret;}
};

3. 计算右侧小于当前元素的个数

在这里插入图片描述

算法思路:

本道题更上一道题的思路是一模一样的, 上一道题我们采用了策略一的方法, 本道题我们采用策略二, 找后面比当前位置元素小的元素的个数, 但是与上一道题不同的是本道题要求返回对应位置的结果, 这是个问题, 如何解决呢, 我们可以采用哈希的思想, 如果使用哈希表那么如果遇到重复的元素, 我们就无法进行解决, 但是我们可以采用这种思想, 创建一个新的数组, 这个数组中存放的是对应位置原始的下标, 然后这个数组跟着nums一起变化, 但是无论怎样变换, 里面的下标还是最原始的下标位置.

在这里插入图片描述

编写代码:

class Solution {vector<int> index;vector<int> ret;int tmpNums[500010];int tmpIndxt[500010];
public:vector<int> countSmaller(vector<int>& nums) {int n = nums.size();ret.resize(n);index.resize(n);for(int i = 0;i < n;i++)index[i] = i;mergeSort(nums,0,n-1);return ret;}void mergeSort(vector<int>& nums,int left,int right){if(left >= right) return;int mid = (left + right)>>1;mergeSort(nums,left,mid);mergeSort(nums,mid+1,right);//至此左右已经处理完, 现在处理一左一右int cur1 = left, cur2 = mid+1, i = 0;while(cur1 <= mid && cur2 <= right){if(nums[cur1] <= nums[cur2]){tmpNums[i] = nums[cur2];tmpIndxt[i++] = index[cur2++];}else{ret[index[cur1]] += right - cur2 + 1;tmpNums[i] = nums[cur1];tmpIndxt[i++] = index[cur1++];}}while(cur1 <= mid){tmpNums[i] = nums[cur1];tmpIndxt[i++] = index[cur1++];}while(cur2 <= right){tmpNums[i] = nums[cur2];tmpIndxt[i++] = index[cur2++];}for(int i = left; i <= right; i++){nums[i] = tmpNums[i - left];index[i] = tmpIndxt[i - left];}}
};

4. 翻转对

在这里插入图片描述

算法思路:

首先我们还是先考虑两个策略. 策略一, 计算后面有多少个元素的两倍比我小, 策略二. 计算前面有多少元素的一半比我大. 不同于前两题, 本道题无法在归并的时候进行计算, 因为这里的比较逻辑和归并的比较逻辑是不同的, 所以这里我在归并逻辑之前采用双指针的方法先进行统计, 然后在进行归并排序.

在这里插入图片描述

在这里插入图片描述

那么首先来看策略一, 在处理完左右之后并排序之后, 我们处理一左一右的情况, 使用双指针, 计算后面有多少元素的两倍比我小, 如果nums[cur1] <= nums[cur2] * 2, 则说明后面元素的两倍比我大, 那么继续移动cur2, 知道找到cur2的位置两倍比我小, 然后进行统计, 此时cur1++, 进行下一次的统计, 这里cur2还需要回退到mid+1的位置嘛?
答案是不需要的, 因为当前位置cur2位置前面元素的两倍都是比我大的, 那cur1++之后降序, 那么一定也是比我大的, 所以直接统计就可以了, 所以整体的时间复杂度为O(NlogN).

class Solution {int tmp[50000];
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 = left;while(cur1 <= mid){while(cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) cur2++;if(cur2 > right) break;//小优化ret += right - cur2 + 1;cur1++;}//降序cur1 = left, cur2 = mid + 1;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 j = left; j <= right; j++)nums[j] = tmp[j]; return ret;}
};

策略二: 找前面有多少元素的一半比我大

在这里插入图片描述

其实更策略一的逻辑是类似的, 只不过这里的数组是升序排列的, 找前面有多少元素的一半比我大, 先让cur1走, 如果/2之后大于nums[cur2]则, cur1++, 找到位置之后统计ret, 然后让cur2++,进行下一次的统计, 此时cur1也不需要回去, cur1之前的位置一半都是比cur2小的, 那么cur2++之后一定还是比cur1小, 所以cur2直接++即可.

class Solution {int tmp[50000];
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 mid = (left + right) >> 1;int ret = 0;ret += mergeSort(nums,left,mid);ret += mergeSort(nums,mid+1,right);int cur1 = left, cur2 = mid + 1, i = left;//升序, 先统计逆序对while(cur2 <= right){while(cur1 <= mid && nums[cur1] / 2.0 <= nums[cur2]) cur1++;if(cur1 > mid) break;ret += mid - cur1 + 1; cur2++;} //合并有序数组cur1 = left, cur2 = mid + 1;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 j = left ; j <= right ; j++)nums[j] = tmp[j];return ret;}
};

相关文章:

算法专题七: 分治归并

目录 1. 排序数组2. 交易逆序对的总数3. 计算右侧小于当前元素的个数4. 翻转对 1. 排序数组 算法思路: 本道题使用归并的思路进行排序, 先讲数组分为左右两个区间, 然后合并两个有序数组. class Solution {vector<int> tmp; public:vector<int> sortArray(vector&…...

一个基于vue功能强大的表格组件--vxe-table的二次封装

基础使用 一个基于 vue 的 PC 端表格组件&#xff0c;支持增删改查、虚拟滚动、懒加载、快捷菜单、数据校验、树形结构、打印导出、表单渲染、数据分页、虚拟列表、模态窗口、自定义模板、渲染器、贼灵活的配置项、扩展接口等… <vxe-grid v-bind"gridOptions1"…...

CSS网页布局(重塑网页布局)

一、实现两列布局 许多网站有一些特点&#xff0c;如页面顶部放置一个大的导航或广告条&#xff0c;右侧是链接或图片&#xff0c;左侧放置主要内容&#xff0c;页面底部放置版权信息等。 一般情况&#xff0c;此类网页布局的两列都有固定的宽度&#xff0c;而且从内容上很容易…...

计算机网络:数据链路层 —— 以太网(Ethernet)

文章目录 局域网局域网的主要特征 以太网以太网的发展100BASE-T 以太网物理层标准 吉比特以太网载波延伸物理层标准 10吉比特以太网汇聚层交换机物理层标准 40/100吉比特以太网传输媒体 局域网 局域网&#xff08;Local Area Network, LAN&#xff09;是一种计算机网络&#x…...

考研前所学c语言02(2024/10/16)

1.一个十进制的数转化为二进制的就是不断除二取余&#xff0c;得到的余数从下到上取 比如123&#xff1a; 结果为&#xff1a; 同理其他的十进制转八进制&#xff0c;十六进制就除八&#xff0c;除十六即可 再比如123转十六进制&#xff1a; 因为余数是11&#xff0c;十六进…...

R语言绘图——坐标轴及图例

掌握坐标轴与图例的设置与调整&#xff0c;对于提升数据可视化的清晰度和可读性至关重要。通过这些工具&#xff0c;可以有效地传达数据背后的故事&#xff0c;提高图表的表现力。 0x01 坐标轴 一、坐标轴的设置 1、修改坐标轴的标签 在ggplot2中&#xff0c;坐标轴是根据数…...

JDK中socket源码解析

目录 1、Java.net包 1. Socket通信相关类 2. URL和URI处理类 3. 网络地址和主机名解析类 4. 代理和认证相关类 5. 网络缓存和Cookie管理类 6. 其他网络相关工具类 2、什么是socket&#xff1f; 3、JDK中socket核心Api 4、核心源码 1、核心方法 2、本地方法 3、lin…...

Ansible自动化运维项目实战指南

Ansible自动化运维项目实战指南 在当今快速发展的IT环境中&#xff0c;运维工作的复杂性和规模性日益增加&#xff0c;传统的手动运维方式已难以满足高效、可靠、可重复性的需求。Ansible作为一款开源的自动化运维工具&#xff0c;凭借其简单易用、无需代理、基于SSH的架构特性…...

MySQL【知识改变命运】10

联合查询 0.前言1.联合查询在MySQL里面的原理2.练习一个完整的联合查询2.1.构造练习案例数据2.2 案例&#xff1a;⼀个完整的联合查询的过程2.2.1. 确定参与查询的表&#xff0c;学⽣表和班级表2.2.2. 确定连接条件&#xff0c;student表中的class_id与class表中id列的值相等2.…...

Java学习教程,从入门到精通, Java 基础语法(4)

1、Java 基础语法 一、Java 简介与开发环境搭建 Java 简介&#xff1a;Java 是一种面向对象的编程语言&#xff0c;具有跨平台、安全、稳定等特点。Java 主要应用于企业级应用、Android 应用开发、大数据处理等领域。开发环境搭建&#xff1a;搭建 Java 开发环境需要安装 JDK…...

反编译工具-Jclasslib的使用,与Java方法调用的探索

这里写目录标题 前言IDEA下查看字节码的两种方法使用idea自带的插件工具安装插件 为什么没有看出方法调用关系原因分析工厂举例 知识补充语言java可移植性 总结 前言 画时序图的时候&#xff0c;我想验证下方法的调用是否写的正确。方法调用不仅涉及到程序的基本逻辑流程&#…...

力扣 简单 876.快慢指针

文章目录 题目介绍题解 题目介绍 题解 class Solution {public ListNode middleNode(ListNode head) {ListNode slow head, fast head;while(fast ! null && fast.next ! null){slow slow.next;fast fast.next.next;}return slow;} }...

FineReport 计算同比增长

1、数据库查询 SELECTt1.年,t1.月,t1.总金额 AS 同期金额,t1.仓库名称,t2.总金额 AS 上期金额 FROMtest t1LEFT JOIN test t2 ON ( t1.年 t2.年 1 ) AND t1.月 t2.月 AND t1.仓库名称 t2.仓库名称2、配置字段 月份字段加后缀 月 数据列加后缀 计算同比增长率 if(LEN(B3)0 …...

从0开始深度学习(12)——多层感知机的逐步实现

依然以Fashion-MNIST图像分类数据集为例&#xff0c;手动实现多层感知机和激活函数的编写&#xff0c;大部分代码均在从0开始深度学习&#xff08;9&#xff09;——softmax回归的逐步实现中实现过 1 读取数据 import torch from torchvision import transforms import torchv…...

如何利用OpenCV和yolo实现人脸检测

在之前的blog里面&#xff0c;我们有介绍OpenCV和yolo的区别&#xff0c;本文就人脸检测为例&#xff0c;分别介绍下OpenCV和yolo的实现方式。 OpenCV实现人脸检测 一、安装 OpenCV 首先确保你已经安装了 OpenCV 库。可以通过以下方式安装&#xff1a; 使用包管理工具安装&…...

015集——c# 实现CAD excel交互(CAD—C#二次开发入门)

第一步&#xff1a;添加引用 程序集—>扩展 namespace WindowsFormsApp2 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){}private void 获取当前excel_Click(object sender, EventArgs e…...

【计网笔记】以太网

经典以太网 总线拓扑 物理层 Manchester编码 数据链路层 MAC子层 MAC帧 DIX格式与IEEE802.3格式 IEEE802.3格式兼容DIX格式 前导码&#xff08;帧开始定界符SOF&#xff09; 8字节 前7字节均为0xAA第8字节为0xAB前7字节的Manchester编码将产生稳定方波&#xff0c;用于…...

Java 入门基础篇14 - java面向对象思想以及特性

学习目标&#xff1a; 一、目标 面向对象思想类和对象对象的创建和使用属性和方法封装 开始学习&#xff1a; 二、编程思想 2.1 什么是编程思想 做人有做人的原则&#xff0c;编程也有编程的原则。这些编程的原则&#xff0c;就叫做编程思想。 2.2 面向过程和面向对象 二…...

第15篇:网络架构优化与综合案例分析

目录 引言 15.1 网络性能优化的方法与工具 15.1.1 带宽管理与流量控制 15.1.2 负载均衡 15.1.3 缓存优化 15.2 网络故障的排查与解决 15.2.1 常用的网络故障排查工具 15.2.2 网络故障排查案例 15.3 网络安全架构的综合设计案例 15.3.1 企业网络安全架构的要求 15.3.…...

UI自动化测试实战

补充&#xff1a;Selenium主要用于Web页面的自动化测试&#xff0c;它可以模拟用户的各种操作&#xff0c;如点击、输入、滚动等&#xff0c;来测试网页的功能。而Appium是一个开源的移动端自动化测试工具。 一、自动化测试实战章节 自动化测试流程测试用例编写项目自动化测试…...

东方智者颜廷利:以哲学思想促进世界和谐与无私奉献

【本社讯】在全球化的今天,东方智慧与哲学思想正逐渐成为促进世界和谐与理解的重要力量。近日,祖籍齐鲁大地山东济南的东方智者颜廷利以其深邃的哲学思想和对人类社会的深刻洞察,引起了国际社会的广泛关注。 颜廷利,一位致力于哲学研究与实践的智者,他的思想跨越古今,融合了东…...

基于 springboot vue停车场管理系统 设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php phython node.js uniapp 微信小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不…...

如何验证ssl私钥和证书是否匹配?

从证书&#xff08;CRT&#xff09;文件提取公钥 openssl x509 -in server.crt -pubkey -noout | openssl sha256从证书签名请求&#xff08;CSR&#xff09;文件提取公钥 openssl req -in server.csr -pubkey -noout | openssl sha256从私钥&#xff08;KEY&#xff09;文件…...

MongoDB的基本操作

&#x1f337;数据库准备 &#x1f388;Mongoshell 1.在指定目录下创建mongodb文件夹、其子文件log和data以及mongodb.log cd /home/ubuntu mkdir -p mongodb/data mkdir -p mongodb/log touch mongodb/log/mongodb.log 执行mongodb命令启动mongdb服务 mongod --dbpath /h…...

spring mvc后端实现过程

文章目录 一、Spring mvc1、controller1.1、LoginController011.2、LoginController 2、service2.1、LoginService2.1、LoginInimplements 3、dao3.1、LoginMapper3.1、LoginMapper.xml 4、实体类 一、Spring mvc 1、controller 控制器层、处理用户的请求和响应&#xff0c; …...

102005

import os os.environ["CUDA_VISIBLE_DEVICES"] "0" # 设定使用的 GPUimport tensorflow as tf from dataset import generate_data import numpy as np from model import enhancednet# 检查 TensorFlow 是否可以识别 GPU gpus tf.config.list_physica…...

Cisco ACI环境给Leaf配置OOB带外管理IP方法

可以通过GUI 或CLI进行配置 通过CLI更简单&#xff0c;和配置传统交换机差不多&#xff0c; ACI中共有3大组件 APIC 控制器 SPINE 核心 LEAF 接入 下面我们将3种角色的带外IP配置方法都列出来 1 APIC配置带外IP This example shows how to configure out-of-band managemen…...

免费送源码:Java+B/S+MySQL springboot电影推荐系统 计算机毕业设计原创定制

摘 要 随着互联网与移动互联网迅速普及&#xff0c;网络上的电影娱乐信息数量相当庞大&#xff0c;人们对获取感兴趣的电影娱乐信息的需求越来越大,个性化的电影推荐系统成为一个热门。然而电影信息的表示相当复杂&#xff0c;己有的相似度计算方法与推荐算法都各有优势&#…...

数据清洗(脚本)

使用脚本清洗数据时&#xff0c;可以根据具体的数据问题选择编程语言&#xff0c;如Shell、Python、SQL等。这里我以 Python&#xff08;Pandas库&#xff09; 和 SQL 为例&#xff0c;演示如何通过脚本进行数据清洗。 1. 使用 Python&#xff08;Pandas库&#xff09; 进行数…...

jmeter中发送post请求遇到的问题

用jmeter发送post请求&#xff0c;把请求参数放在Body Data处&#xff0c;参数都写得正确&#xff0c;但没想到结果每次都报错&#xff0c;直接响应结果乱七八糟&#xff0c;改成用Parameters,反而不乱报错了。 上图 请求里如下 另外一些请求也是这样 这个响应结果也是错误的…...