数据结构与算法(四)分治算法(Java)

目录

    • 一、简介
      • 1.1 背景
      • 1.2 定义
      • 1.3 步骤
      • 1.4 时间复杂度
    • 二、经典示例
      • 2.1 二分搜索
      • 2.2 快速排序
      • 2.3 归并排序(逆序数)
      • 2.4 最大子序列和

一、简介

1.1 背景

在学习分治算法之前,我们先来举一个例子。

假如你有一个存钱罐,过年家人给的钱都会放到存钱罐中。当我们想要清点存钱罐中的钱时,一堆钱混乱的放在一起很难清点,并且容易算错。那我们可以这样,先将存钱罐中的钱分成几小份,然后再求和就可以了

在这里插入图片描述

如果我们还是觉得各个部分的钱数太大,依然可以进行划分然后合并,比如每凑够100元为一组等。梳理下思路,我们之所以这么做是因为以下两点:

  1. 划分后的子问题更易求解;
  2. 父问题的结果可以直接由子问题的结果计算得到。

其实这就是一种分治的思想。

1.2 定义

分治算法:是一种 将一个问题分解为多个子问题,分别求解这些子问题 的解决方法,主要用于递归计算中

1.3 步骤

具体来说,分治算法通常包括三个步骤:

  1. 分解原问题为若干子问题;
  2. 解决这些子问题,递归地运用分治算法;
  3. 合并这些子问题的解为一个整体。

1.4 时间复杂度

分治算法的时间复杂度通常为 O(nlogn)


二、经典示例

分治算法的经典使用示例包括:

  • 二分搜索
  • 快速排序
  • 归并排序
  • 最大子序列和
  • 其他:最近点对、大整数乘法、Strassen矩阵乘法、棋盘覆盖、线性时间选择、循环赛日程表、汉诺塔等。

2.1 二分搜索

二分查找

二分搜索是分治算法的一个示例,只不过二分搜索有着自己的特殊性:

  • 序列有序;
  • 结果为一个值。

思路:

  • 先将一个完整的区间分成两个区间;
  • 两个区间本应单独找值然后确认结果,但是通过有序的区间可以直接确定结果所在区间,然后对结果所在区间进行再次划分;
  • 直到找到值。

代码实现:

实现方式有递归和非递归两种,但是非递归用得更多一些:

/**
 * 二分查找
 * @param nums 数组
 * @param target 目标值
 * @return 位置
 */
public int binarySearch(int[] nums, int target) {
    // 超出范围
    if (target < nums[0] || target > nums[nums.length - 1]) {
        return -1;
    }
    // 判断边界
    if (target == nums[0]) {
        return 0;
    }
    if (target == nums[nums.length - 1]) {
        return nums.length - 1;
    }
    // 二分查找
    int left = 0, right = nums.length - 1;
    int index = 1;
    while (left < right - 1) {
        System.out.println("查找次数:" + index++);
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            return mid;
        } else if (target < nums[mid]) {
            right = mid;
        } else {
            left = mid;
        }
    }
    return -1;
}

2.2 快速排序

快速排序,简称 快排,也是分治算法的一个示例。

思路:

  • 快排每一次遍历会选定一个数,将比这个数小得放左面,比这个数大的放右面;
  • 然后递归分治求解两个子区间;
  • 快排在划分时就做了很多工作,当划分到最底层的时候,最后的序列值就是排序完的值。

快排是一种分而治之的体现。

在这里插入图片描述

代码实现:

public int[] sortArray(int[] nums) {
    quickSort(nums, 0, nums.length - 1);
    return nums;
}
/**
 * 快速排序
 * @param nums  数组
 * @param left  起始位置
 * @param right 结束位置
 */
private void quickSort(int[] nums, int left, int right) {
    if (left > right) {
        return;
    }
    int l = left;
    int r = right;
    // 中心轴
    int pivot = nums[l];
    while (l < r) {
        // 找到第一个小于k的值
        while (nums[r] >= pivot && r > l) {
            r--;
        }
        nums[l] = nums[r];
        // 找到第一个大于k的值
        while (nums[l] <= pivot && l < r) {
            l++;
        }
        nums[r] = nums[l];
    }
    nums[l] = pivot;
    quickSort(nums, left, r - 1);
    quickSort(nums, l + 1, right);
}

2.3 归并排序(逆序数)

排序数组

快速排序在划分的时候做了很多工作,而归并排序则恰恰相反。

思想:

  • 先按照数量均匀划分为两块区域;
  • 两块区域再各自进行划分,直到每块区域长度为1;
  • 合并的时候再两两进行有序的合并。两个有序序列的合并仅需 O(n) 级别的时间复杂度即可完成。

而逆序数再归并排序基础上变形同样也是分治思想求解。

在这里插入图片描述

代码实现:

public int[] sortArray(int[] nums) {
    mergeSort(nums, 0, nums.length - 1);
    return nums;
}

/**
 * 归并排序
 * @param nums  数组
 * @param left  起始位置
 * @param right 结束位置
 */
private void mergeSort(int[] nums, int left, int right) {
    int mid = (left + right) / 2;
    if (left < right) {
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);
        merge(nums, left, mid, right);
    }
}

/**
 * 两两排序
 * @param nums  数组
 * @param left  起始位置
 * @param mid   中间位置
 * @param right 结束位置
 */
private void merge(int[] nums, int left, int mid, int right) {
    int[] arr = new int[right - left + 1];
    int l = left;
    int r = mid + 1;
    int index = 0;
    while (l <= mid && r <= right) {
        if (nums[l] <= nums[r]) {
            arr[index++] = nums[l++];
        } else {
            arr[index++] = nums[r++];
        }
    }
    while (l <= mid) {
        arr[index++] = nums[l++];
    }
    while (r <= right) {
        arr[index++] = nums[r++];
    }
    System.arraycopy(arr, 0, nums, left, arr.length);
}

2.4 最大子序列和

最大子数组和

题目:

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

思路:

最大子序列和问题,我们可以使用 动态规划 的解法,也可以使用 分治算法 来解决问题。最大子序列和 在合并的时候并不是简单的合并,因为 子序列和 涉及到一个长度的问题,所以 正确结果不一定全在 最左侧 或 最右侧,可能出现结果的区域为:

  • 完全在中间的左侧
  • 完全在中间的右侧
  • 包含中间左右两个节点的一个序列

在这里插入图片描述

代码实现:

public int maxSubArray(int[] nums) {
    return maxSub(nums, 0, nums.length - 1);
}

private int maxSub(int[] nums, int left, int right) {
    if (left == right) {
        return nums[left];
    }
    int mid = (left + right) / 2;
    // 计算完全在mid左边的最大值
    int maxSubLeft = maxSub(nums, left, mid);
    // 计算完全在mid右边的最大值
    int maxSubRight = maxSub(nums, mid + 1, right);

    // 计算包含mid的最大值
    int tmpMaxLeft = nums[mid];
    int tmpLeftSum = 0;
    for (int i = mid; i >= left; i--) {
        tmpLeftSum += nums[i];
        tmpMaxLeft = Math.max(tmpMaxLeft, tmpLeftSum);
    }
    int tmpMaxRight = nums[mid + 1];
    int tmpRightSum = 0;
    for (int i = mid + 1; i <= right; i++) {
        tmpRightSum += nums[i];
        tmpMaxRight = Math.max(tmpMaxRight, tmpRightSum);
    }
    int maxSubCenter = tmpMaxLeft + tmpMaxRight;

    if (maxSubCenter >= maxSubLeft && maxSubCenter >= maxSubRight) {
        return maxSubCenter;
    } else {
        return Math.max(maxSubLeft, maxSubRight);
    }
}

整理完毕,完结撒花~ 🌻





参考地址:

1.「五大常用算法」一文搞懂分治算法,https://zhuanlan.zhihu.com/p/328368839

2.十大经典排序算法及动图演示,https://zhuanlan.zhihu.com/p/449501682

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】开源:Boost进程间通信库InterProcess配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Boost进程间通信库InterProcess配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一…

Java实现简单的王者荣耀游戏

一、创建新项目 首先创建一个新的项目&#xff0c;并命名为wangzherongyao。 其次在飞翔的鸟项目下创建一个名为img的文件夹用来存放游戏相关图片。详细如下图&#xff1a; 二、游戏代码 1、创建怪物类 1.bear&#xff1a; package beast;import wangzherogyao.GameFrame;…

听说这样寄快递会很省钱!速来收藏!便宜寄快递!

哈喽&#xff0c;小伙伴们&#xff0c;今天介绍一个寄快递省钱的小妙招。话不多说&#xff0c;小编直接开整&#xff01; 在闪侠惠递这个快递折扣平台下单送快递&#xff0c;不仅方便&#xff0c;而且运费更便宜。平台整合了京东、顺丰、圆通、申通、极兔、等快递公司可供选择…

Oracle 中换行chr(10)、回车chr(13)

一、前言 chr(n)&#xff1a;返回 ascii 值对应的字符。 ascii(char)&#xff1a;返回字符 char对应的ascii 值。 chr(n) 和 ascii(char) 作用刚好是相反的。 SQL> select chr(65) from dual; 控制台显示&#xff1a;ASQL> select ascii(A) from dual; 控制台显示&am…

最受好评的 Android 数据恢复软件工具

在本文中&#xff0c;您将找到适用于 Windows 的最佳 Android 数据恢复软件&#xff0c;以从 Android 恢复丢失或删除的文件。 Android 设备被广泛使用。但数据丢失在 Android 手机中也很常见。生活中&#xff0c;我们经常清理内存较小的安卓手机中的无效垃圾短信&#xff0c;…

Temu拼多多跨境电商,产品合规要求,需要的检测报告证书你了解多少?

Temu拼多多跨境电商&#xff0c;产品合规要求&#xff0c;需要的检测报告证书你了解多少&#xff1f;Temu 拼多多跨境电商 自拼多多Temu登录美国超级碗后&#xff0c;Temu已经超过亚马逊和沃尔玛&#xff0c;成为美国下载量最高的购物应用&#xff0c;Temu已然成为近期美国人民…

Netty网络编程

入门案例 1、服务器端代码 public class HelloServer {public static void main(String[] args) {// 1、启动器&#xff0c;负责装配netty组件&#xff0c;启动服务器new ServerBootstrap()// 2、创建 NioEventLoopGroup&#xff0c;可以简单理解为 线程池 Selector.group(n…

5. Jetson Orin Nano CUDA 配置

5. Jetson Orin Nano CUDA 配置 1&#xff1a;安装Jtop jtop安装主要有以下三个步骤&#xff1a; 安装pip3 我们需要使用pip3来安装jtop&#xff0c;所以先安装pip3 sudo apt install python3-pip安装jtop sudo -H pip3 install -U jetson-stats运行jtop服务 sudo -H pip3 in…

Temu数据面板:Temu商家必备的数据分析工具

在Temu这个电商平台上&#xff0c;越来越多的商家意识到数据分析的重要性。数据分析可以帮助商家更好地了解店铺的运营情况&#xff0c;从而制定更有效的运营策略&#xff0c;提高销售业绩。而在这个过程中&#xff0c;Temu数据面板成为了一个不可或缺的工具。 先给大家推荐一款…

软件测试具体人员分工

最近看了点敏捷测试的东西&#xff0c;看得比较模糊。一方面是因为没有见真实的环境与流程&#xff0c;也许它跟本就没有固定的模式与流程&#xff0c;它就像告诉人们要“勇敢”“努力”。有的人在勇敢的面对生活&#xff0c;有些人在勇敢的挑战自我&#xff0c;有些人在勇敢的…

springboot实现邮箱发送功能

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 邮箱效果图一、pom配置二、页面编写三、配置yml四、邮件工具类五、测试发送 邮箱效果图 1.可以利用在出现问题进行邮箱提醒 2.编写html 用于在邮箱中展示的样式 提示…

使用Java语言判断一个数据类型是奇数还是偶数

判断一个数字类型是奇数&#xff0c;还是偶数&#xff0c;只需要引入Scanner类&#xff0c;然后按照数据类型的定义方式进行定义&#xff0c;比较是按照与2进行整除后的结果&#xff1b;如果余数为零&#xff0c;则代表为偶数&#xff0c;否则为奇数。 import java.util.Scann…

大数据 - MapReduce:从原理到实战的全面指南

本文深入探讨了MapReduce的各个方面&#xff0c;从基础概念和工作原理到编程模型和实际应用场景&#xff0c;最后专注于性能优化的最佳实践。 一、引言 1.1 数据的价值与挑战 在信息爆炸的时代&#xff0c;数据被视为新的石油。每天都有数以百万计的数据被生成、存储和处理&…

微软推出AI助手Copilot的正式版本;ChatGPT:七位研究人员分享他们的观点

&#x1f989; AI新闻 &#x1f680; 微软推出AI助手Copilot的正式版本 摘要&#xff1a;微软宣布其AI助手Copilot正式上线&#xff0c;此前Copilot的预览版已成为很多用户的日常AI伴侣。此次上线后&#xff0c;Copilot将继续提供AI驱动的网络聊天体验&#xff0c;并具备商业…

推荐系统-01-基于协同过滤的图书推荐系统(包括数据和代码)

文章目录 0. 数据下载1. 背景描述2. 预测目的3. 数据总览4. 开始处理4.1 图书4.1.1 yearOfPublication4.1.2 publisher 4.2 用户数据集4.2.1 userID4.2.2 Age 4.3 评级数据集4.3.1 统计 5. 基于简单流行度的推荐系统6. 基于协同过滤的推荐系统6.1 基于用户的协同过滤6.2 基于项…

LangChain学习指南(一)——Model IO

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Langchain是什么&#xff1f;二、官方文档Langchain这么长&#xff0c;我怎么看&#xff1f;三、Model IO2.1.1prompt2.1.2LLM2.1.3 OutputParsers 前言 本…

Csharp(C#)无标题栏窗体拖动代码

C#&#xff08;C Sharp&#xff09;是一种现代、通用的编程语言&#xff0c;由微软公司在2000年推出。C#是一种对象导向的编程语言&#xff0c;它兼具C语言的高效性和Visual Basic语言的易学性。C#主要应用于Windows桌面应用程序、Windows服务、Web应用程序、游戏开发等领域。C…

Jmeter接口自动化测试 —— Jmeter变量的使用

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

Linux:dockerfile编写搭建tomcat练习(9)

我使用的httpyum仓库 本地使用了5个文件&#xff0c;tomcat使用的官网解压直接用的包】 Dockerfile 主配置文件 基于centos基础镜像 jdk1.8.0_91 java环境 run.sh 启动脚本 centos.repo 仓库文件 tomcat 源码包 vim Dockerfile写入FROM centos MAINTAINER ta…