归并分治 计算数组的小和 + 图解 + 笔记

news/2024/5/17 18:13:37 标签: 算法, 数据结构, 归并排序, 归并分治, 小和

 归并分治 前置知识:讲解021-归并排序

归并排序 图解 递归 + 非递归 + 笔记-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/134338789?spm=1001.2014.3001.5501原理:

  • (1)思考一个问题在大范围上的答案,是否等于,左部分的答案 + 右部分的答案 + 跨越左右产生的答案
  • (2)计算“跨越左右产生的答案”时,如果加上左、右各自有序这个设定,会不会获得计算的便利性
  • (3)如果以上两点都成立,那么该问题很可能被归并分治解决(话不说满,因为总有很毒的出题人)
  • (4)求解答案的过程中只需要加入归并排序的过程即可,因为要让左、右各自有序,来获得计算的便利性

补充:

  • (1)一些用归并分治解决的问题,往往也可以用线段树,树状数组等解法。时间复杂度也都是最优解,这些数据结构都会在【扩展】
  • (2)本书讲述的题目都是归并分治的常规题,难度不大。归并分治不仅可以解决简单问题,还可以解决很多较难的问题,只要符合上面说的特征。比如二维空间里任何两点间的最短距离问题,这个内容会在【挺难】课程阶段里讲述。顶级公司考这个问题的也很少,因为很难,但是这个问题本身并不冷门,来自《算法导论》原题
  • (3)还有一个常考的算法“整块分治”。会在【必备】课程阶段讲到

举个栗子】假设数组 s = [1,3,5,2,4,6],给定一个数组arr,实现函数返回arr的“小和

    在s[0]的左边所有 <= s[0]的数的总和为0
    在s[1]的左边所有 <= s[1]的数的总和为1
    在s[2]的左边所有 <= s[2]的数的总和为4
    在s[3]的左边所有 <= s[3]的数的总和为1
    在s[4]的左边所有 <= s[4]的数的总和为6
    在s[5]的左边所有 <= s[5]的数的总和为15
所以s数组的 小和” 为:0 + 1 + 4 + 1 + 6 + 15 = 27

  • "小和"问题是,当我 j 来到一个位置的时候,你的左侧 i 去给我划答案  

C++代码:

#include <iostream>
using namespace std;
#include <vector>

// 返回跨左右产生的小和累加和,左侧有序、右侧有序,让左右两侧整体有序
// arr[left...mid] arr[mid+1...right]
long merge(vector<int>& arr,int left, int mid, int right) {
	int n = right - left + 1;
	vector<int> help(n, 0);
	// 统计部分
	long ans = 0;
	for (int j = mid + 1, i = left, sum = 0; j <= right; j++) {
		while (i <= mid && arr[i] <= arr[j]) {
			sum += arr[i++];
		}
		ans += sum;
	}
	// 正常merge
	int i = 0;
	int a = left;
	int b = mid + 1;
	while (a <= mid && b <= right) {
		help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
	}
	while (a <= mid) {
		help[i++] = arr[a++];
	}
	while (b <= right) {
		help[i++] = arr[b++];
	}
	for (i = 0; i < n; i++) {
		arr[i+left] = help[i];
	}
	return ans;
}

// 结果比较大,用 int 会溢出的,所以返回 long 类型
// 特别注意溢出这个点,笔试常见坑
// 返回arr[left...right]范围上,小和的累加和,同时把arr[left...right]变有序
long smallSum(vector<int>&arr, int left, int right) {
	if (left == right) return 0;
	//int mid = (left + right) / 2;
	int mid = left + ((right - left) >> 1);
	return smallSum(arr,left, mid) + smallSum(arr,mid + 1, right) + merge(arr,left, mid, right);
}

int main() {
	vector<int>arr = { 7,7,6,2,6,5,4,9 };
	//vector<int>arr = { 1, 3, 5, 2, 4, 6 };
	int n = arr.size();
	cout<<"该数组的小和为:"<<smallSum(arr,0, n - 1)<<endl;
	system("pause");
	return 0;
}

计算数组的小和__牛客网 (nowcoder.com)icon-default.png?t=N7T8https://www.nowcoder.com/questionTerminal/edfe05a1d45c4ea89101d936cac32469?f=discussion

  •  实战牛客网[编程题]计算数组的小和
#include <iostream>
#include <vector>
using namespace std;
// 返回跨左右产生的小和累加和,左侧有序、右侧有序,让左右两侧整体有序
// arr[left...mid] arr[mid+1...right]
long merge(vector<int>& arr, int left, int mid, int right) {
	int n = right - left + 1;
	vector<int> help(n, 0);
	// 统计部分
	long ans = 0;
	for (int j = mid + 1, i = left, sum = 0; j <= right; j++) {
		while (i <= mid && arr[i] <= arr[j]) {
			sum += arr[i++];
		}
		ans += sum;
	}
	// 正常merge
	int i = 0;
	int a = left;
	int b = mid + 1;
	while (a <= mid && b <= right) {
		help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
	}

	while (a <= mid) {
		help[i++] = arr[a++];
	}
	while (b <= right) {
		help[i++] = arr[b++];
	}
	for (i = 0; i < n; i++) {
		arr[i + left] = help[i];
	}
	return ans;
}


// 结果比较大,用 int 会溢出的,所以返回 long 类型
// 特别注意溢出这个点,笔试常见坑
// 返回arr[left...right]范围上,小和的累加和,同时把arr[left...right]变有序
long smallSum(vector<int>& arr, int left, int right) {
	if (left == right) return 0;
	//int mid = (left + right) / 2;
	int mid = left + ((right - left) >> 1);
	return smallSum(arr, left, mid) + smallSum(arr, mid + 1, right) + merge(arr, left, mid, right);
}

int main() {
	int n;
	cin >> n;
	vector<int> arr(n, 0);
	for (int i = 0; i < n; i++) cin >> arr[i];
	cout << smallSum(arr, 0, n - 1) << endl;
	return 0;
}

参考和推荐视频:

算法讲解022【必备】归并分治_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1L14y1B7ef/?spm_id_from=333.788.recommend_more_video.-1&vd_source=a934d7fc6f47698a29dac90a922ba5a3


http://www.niftyadmin.cn/n/5171772.html

相关文章

Sprint Boot 学习路线 4

微服务 Spring Microservices是一个框架&#xff0c;它使用Spring框架更容易地构建和管理基于微服务的应用程序。微服务是一种架构风格&#xff0c;其中一个大型应用程序被构建为一组小型、独立可部署的服务。每个服务具有明确定义的职责&#xff0c;并通过API与其他服务通信。…

【沐风老师】3DMAX克隆修改器插件教程

3DMAX克隆修改器插件&#xff0c;它通过增量平移、旋转和缩放输入几何体来创建对象的副本。在某些方面&#xff0c;它类似于 3ds Max 的内置阵列工具&#xff0c;但有一个主要优点 -克隆是完全参数化的&#xff0c;因此您可以随时更改重复项的数量及其分布。其他功能包括随机变…

vmware开启ipv6

说明 在 ipv4 基础上配置ipv6网络。 分享 大数据博客列表开发记录汇总个人java工具库 项目https://gitee.com/wangzonghui/object-tool 包含json、string、集合、excel、zip压缩、pdf、bytes、http等多种工具&#xff0c;欢迎使用。 vm开启ipv6 设置vmware 打开vmware点击编…

pyqt5学习-01 UI界面创建以及生成python代码

前提 环境搭建 打开designer 选择创建主窗体&#xff0c;拖入一个按钮 保存主窗体UI文件为firstMainWin.ui 将UI文件转化为python文件 # 可以把E:\Python\envs\pyqt5stu\Scripts\pyuic5.exe添加到环境变量中 E:\Python\envs\pyqt5stu\Scripts\pyuic5.exe -o firstMainWin.…

记事本简单运行java代码,理解程序运行

1.记事本创建一个文件, 把后缀.txt改为.java 如果没有显示尾缀, 勾选出文件扩展名 2.在文件里面编辑java代码并保存 3.在当前目录打开cmd 4.执行 javac Test.java 会生成好编译的.class文件 5.执行下面代码, 就成功得到j编写ava打印的代码 java Test 6.注意上面的中文在cmd中…

ARM Cortex-M体系寄存器结构

General-Purpose Registers (R0-R12) 这些寄存器主要用于存储临时变量。在大多数情况下&#xff0c;指令可以使用任何这些寄存器来执行操作。 Stack Pointer (SP) 该寄存器指向当前的堆栈顶部。ARM Cortex-M 体系结构提供两个堆栈指针&#xff1a;MSP (Main Stack Pointer) 和…

vue.cli 中怎样使用自定义的组件

目录 创建自定义组件 注册并使用自定义组件 全局注册自定义组件 使用 Props 传递数据 总结 前言 在Vue CLI中使用自定义组件是构建交互式和模块化Web应用的重要一环。Vue CLI为开发者提供了使用自定义组件的灵活性和简便性。通过Vue CLI&#xff0c;你可以创建、注册和使…

Flink之Table API SQL连接器

连接器 Table API & SQL连接器1.概述2.支持连接器 DataGen连接器1.概述2.SQL客户端执行3.Table API执行 FileSystem连接器1.创建FileSystem映射表2.创建source数据源表3.写入数据4.解决异常5.查询fileTable6.查看HDFS Kafka连接器1.添加kafka连接器依赖2.重启yarn-session、…