0

0

将给定数组转换为目标数组所需的最少分组数

心靈之曲

心靈之曲

发布时间:2025-11-22 17:18:06

|

287人浏览过

|

来源于php中文网

原创

将给定数组转换为目标数组所需的最少分组数

本文探讨了如何通过最少次数的切割和重新排列,将一个唯一值数组转换为另一个目标数组。核心方法是利用哈希映射记录目标数组中元素的索引位置,然后遍历源数组。通过比较当前元素在目标数组中的索引与前一个元素的索引是否连续,来识别并计数连续的、无需内部重排的片段。当序列中断时,即为一个新分组的开始,最终统计出所需的最少分组数量。

问题描述

给定两个具有唯一整数值的数组 arr1 和 arr2,它们的长度相同。目标是找出将 arr1 切割成最少数量的连续片段,然后通过重新排列这些片段,使其能够组合成 arr2。

例如,如果 arr1 = [1, 4, 3, 2] 且 arr2 = [1, 2, 4, 3]: 我们可以将 arr1 切割为 (1), (4, 3), (2) 三个片段。 然后通过重新排列这些片段 (1), (2), (4, 3),可以得到 [1, 2, 4, 3]。 因此,所需的最少分组数是 3。

约束条件:

  • 数组中的所有值都是唯一的。
  • 两个数组的长度相同,最大可达 1000。
  • 数组值均为整数。

核心思想与算法

由于数组中的所有元素都是唯一的,这意味着每个元素在 arr1 和 arr2 中都只出现一次。解决此问题的关键在于理解“连续片段”的定义。一个片段 (x, y, z) 是连续的,当且仅当 x 在 arr2 中的索引是 i,y 在 arr2 中的索引是 i+1,z 在 arr2 中的索引是 i+2,以此类推。如果 arr1 中的两个相邻元素在 arr2 中也保持相邻且顺序一致,那么它们可以属于同一个片段。否则,就需要一个新的片段。

基于此,我们可以采用以下步骤来确定最少分组数:

  1. 建立目标数组索引映射: 为了快速查找 arr1 中每个元素在 arr2 中的目标位置,我们首先创建一个哈希映射(Map),将 arr2 中的每个元素值映射到它在 arr2 中的索引。

    绘蛙AI商品图
    绘蛙AI商品图

    电商场景的AI创作平台,无需高薪聘请商拍和文案团队,使用绘蛙即可低成本、批量创作优质的商拍图、种草文案

    下载
  2. 遍历源数组并计数:

    • 初始化一个计数器 count 为 1,因为 arr1 的第一个元素总是会开始一个新的片段。
    • 获取 arr1 第一个元素在 arr2 中的目标索引,将其存储为 prevIndex。
    • 从 arr1 的第二个元素开始遍历:
      • 对于当前元素,通过哈希映射获取它在 arr2 中的目标索引,将其存储为 nextIndex。
      • 比较 nextIndex 和 prevIndex + 1:
        • 如果 nextIndex == prevIndex + 1,这表示当前元素在 arr2 中紧接着前一个元素,它们形成了一个连续的、顺序正确的片段。我们只需更新 prevIndex = nextIndex,继续扩展当前片段。
        • 如果 nextIndex != prevIndex + 1,这表示当前元素在 arr2 中的位置不紧接着前一个元素,或者说它们之间存在“断裂”。这意味着我们必须从当前元素开始一个新的片段。因此,我们需要将 count 加 1,并更新 prevIndex = nextIndex。
    • 遍历结束后,count 的值就是所需的最少分组数。

示例代码实现 (Java)

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class ArrayGroupingConverter {

    /**
     * 计算将 arr1 转换为 arr2 所需的最少分组数。
     *
     * @param arr1 源数组
     * @param arr2 目标数组
     * @return 最少分组数
     */
    public static int process(int[] arr1, int[] arr2) {
        // 步骤 1: 建立目标数组的索引映射
        // key: 元素值, value: 该元素在 arr2 中的索引
        Map indexByValue = mapIndices(arr2);

        // 步骤 2: 遍历源数组并计数
        // 至少有一个分组,即 arr1 的第一个元素
        int count = 1; 

        // 获取 arr1 第一个元素在 arr2 中的目标索引
        int prevIndex = indexByValue.get(arr1[0]);

        // 从 arr1 的第二个元素开始遍历
        for (int i = 1; i < arr1.length; i++) {
            // 获取当前元素在 arr2 中的目标索引
            int nextIndex = indexByValue.get(arr1[i]);

            // 检查当前元素是否与前一个元素在 arr2 中保持连续顺序
            if (nextIndex == prevIndex + 1) {
                // 如果连续,更新 prevIndex,继续当前分组
                prevIndex++;
            } else {
                // 如果不连续,说明需要开始一个新的分组
                prevIndex = nextIndex; // 新分组的起始索引
                count++;               // 分组数加一
            }
        }

        return count;
    }

    /**
     * 辅助方法:将数组元素映射到其索引。
     *
     * @param arr 要映射的数组
     * @return 元素值到其索引的映射
     */
    public static Map mapIndices(int[] arr) {
        return IntStream.range(0, arr.length) // 生成从 0 到 arr.length-1 的整数流
            .boxed() // 将 int 转换为 Integer 对象流
            .collect(Collectors.toMap( // 收集到 Map 中
                i -> arr[i], // key 是数组元素的值
                Function.identity() // value 是该元素的索引 i
            ));
    }

    public static void main(String[] args) {
        int[] arr1 = {1, 4, 3, 2};
        int[] arr2 = {1, 2, 4, 3};
        System.out.println("源数组: " + Arrays.toString(arr1));
        System.out.println("目标数组: " + Arrays.toString(arr2));
        System.out.println("所需的最少分组数: " + process(arr1, arr2)); // 预期输出: 3

        int[] arr3 = {1, 2, 3, 4};
        int[] arr4 = {1, 2, 3, 4};
        System.out.println("源数组: " + Arrays.toString(arr3));
        System.out.println("目标数组: " + Arrays.toString(arr4));
        System.out.println("所需的最少分组数: " + process(arr3, arr4)); // 预期输出: 1

        int[] arr5 = {4, 3, 2, 1};
        int[] arr6 = {1, 2, 3, 4};
        System.out.println("源数组: " + Arrays.toString(arr5));
        System.out.println("目标数组: " + Arrays.toString(arr6));
        System.out.println("所需的最少分组数: " + process(arr5, arr6)); // 预期输出: 4
    }
}

运行示例及输出

源数组: [1, 4, 3, 2]
目标数组: [1, 2, 4, 3]
所需的最少分组数: 3
源数组: [1, 2, 3, 4]
目标数组: [1, 2, 3, 4]
所需的最少分组数: 1
源数组: [4, 3, 2, 1]
目标数组: [1, 2, 3, 4]
所需的最少分组数: 4

复杂度分析

  • 时间复杂度:

    • mapIndices 方法需要遍历 arr2 一次,将所有元素及其索引放入哈希映射中。这需要 O(N) 的时间,其中 N 是数组的长度。
    • process 方法需要遍历 arr1 一次。在每次迭代中,从哈希映射中查找元素索引的操作平均为 O(1)。
    • 因此,总的时间复杂度为 O(N) + O(N) = O(N)。
  • 空间复杂度:

    • mapIndices 方法创建了一个哈希映射,存储了 arr2 中所有 N 个元素及其索引。这需要 O(N) 的空间。
    • process 方法只使用了几个常数空间变量。
    • 因此,总的空间复杂度为 O(N)。

注意事项与总结

  • 唯一性是关键: 题目中明确指出数组值是唯一的,这是算法能够成立的基础。如果存在重复值,则需要更复杂的逻辑来处理元素的匹配和片段的定义。
  • 连续性判断: 算法的核心在于 nextIndex == prevIndex + 1 的判断。这准确地捕捉了在目标数组中元素是否保持了连续的相对顺序。
  • 起始分组: count 初始化为 1 是因为无论如何,arr1 的第一个元素都会开始一个片段。后续的判断只是决定这个片段是否能扩展,或者是否需要开启一个新的片段。
  • 适用场景: 这种方法适用于需要通过最小化切割操作来重排序列的问题,尤其是在元素唯一且目标顺序明确的情况下。

通过这种基于索引映射和连续性检查的方法,我们可以高效地计算出将一个数组转换为另一个数组所需的最少分组数,从而实现问题的优化求解。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.11.20

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

75

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

36

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

60

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.27

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

407

2023.08.14

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

9

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

107

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

13

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.9万人学习

C# 教程
C# 教程

共94课时 | 7.7万人学习

Java 教程
Java 教程

共578课时 | 51.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号