分治算法题之数组元素求和

EduCoder实训机器学习 头歌实训 阅读详情

        前几天逛论坛,看到一个帖子里说到一个算法题目: 给出1到19的连续递增自然数数组,求所有和为20的可能元素加法组合。每个加法组合中的元素不能重复使用。 题目只是给出个元素求和一个特例,我们可以把题目定义的更宽泛些。给定一个连续的自然数数组a(a[i]>0,a.length>0),求所有数据元素的加法运算,使得其和等于另一个给定的整数数值m (m>0)。

        这是个分治算法的场景,题目的出发点如下

  • 得到给定的m,可能要通过多步加法运算得到。一次性得出结果往往很难。但我们可以将加法步骤进行拆分,每次拆分可以穷举出所有的可能排列。比如m=10,那么两步加法得到10的排列会有几种? 很明显 [0,10],[1,9],[2,8],[3,7],[4,6],[5,5],[6,4],[7,3],[8,2],[9,1],[10,0] 就是所有的穷举结果。
  • 在每次进行步骤一的加法拆分时,可以将数组同时按照中间位置进行拆分。并将步骤一得到的加法穷举结果代入。如此递归,直至数组中只有一个元素存在。

       如下以a=[1,2,3,4,5,6,7,8,9], m=10为例对步骤进行一下说明

       1. 将m进行两步加法划分得到[0,10],[1,9],[2,8],[3,7],[4,6],[5,5],[6,4],[7,3],[8,2],[9,1],[10,0] 所有的穷举结果。

       2. 将数组从中间数进行划分得到两个子数组left = [1,2,3,4,5] ,right =[6,7,8,9],如下图所示

       3. 对所有加法组合及对应子数组进行递归拆分求解,这里以加法组合[10,0]为例进行展开,如下图示


             如上图所示, 子数组[6,7,8,9] 求和为0的可能组合很明显根本不需要去求。我们只关心子数组[1,2,3,4,5] 求和为10的所有组合即可。那同样对10和子数组[12,3,4,5]进行同样的拆分。我们还可以继续拆分,直到数组中只有一个元素为止。但在这一步,我们直观上已经很明显能看出可能的组合结果如下图


4. 将数组[1,2,3,4,5] = 10,和[6,7,8,9] = 0 两个数组的求解结果进行合并,就是我们所要的对于[10,0]这个加法拆分方式的结果。

代码如下

import java.util.Arrays;

public class EqualsTeller {

	/**
	 * 将两个一维数组left[m],right[j]合并成m[m+j]数组。
	 */
	private int[] merge(int[] left,int[] right){
		int[] m = new int[left.length + right.length];
		System.arraycopy(left,0,m,0,left.length);
		System.arraycopy(right, 0, m, left.length, right.length);
		return m;
	}
	/**
	 * 将二维数组left[m][x] 和 right[n][y]数组合并为二维数组 merge[m*n][x+y]
	 */
	private int[][] crossMerge(int[][] left,int[][] right){
		
		if (left[0][0] == 0)
			return right;
		if (right[0][0] == 0)
			return left;
		
		int[][] m = new int[left.length * right.length][];
		int row = 0;
		for (int i=0;i< left.length;i++){
			for (int j=0;j< right.length;j++){
				int[] l = left[i];
				int[] r = right[j];
				m[row] = merge(l,r);
				row++;
			}
		}
		
		return m;
		
		
	}
	
	private int[][] appendMerge(int[][] left,int[][] right){
		int[][] m = new int[left.length + right.length][];
		for (int i=0;i< left.length;i++){
			     m[i] = left[i];
		}
		for (int i=left.length;i< m.length;i++){
			    m[i] = right[i - left.length];

		}
		
		return m;
		
		
	}
	
	
	/**
	 * 给定数组 a,和一个大于零的数值sum. 找出所有合计值为sum的加法运算,加法运算中所有的元素必须来自数组a,且不能重复。
	 * @param a 给定的数组。数组中的元素必须是连续的,递增的。例如[1,2,3,4,5,6,7,8,9]
	 * @param sum 假定的合计值。要求大于零。
	 * @return 二维数组,含有所有可能加法组合的方案。
	 */
	private int[][] findEqualFormula(int[] a,int sum){
		boolean valid_flag = false;
		int[][] m = new int[0][0];
		
		if (sum == 0){ //如果传入的sum是零的话,则无需再当前数组a中寻找可能的加法解。直接返回{{0}};
			m = new int[1][1];
		    m[0] = new int[]{0};
		}
		else
        if (a.length > 1){
            if (sum < a[0]){ //小于数组中最小值,返回{{-1}}即当前数组无法得出对应的Sum值。
            	m = new int[1][1];
    		    m[0] = new int[]{-1};
            }else if (sum > (a[0] + a[a.length -1])*(a.length)/2){ //大于数组和,返回{{-1}}即当前数组无法得出对应的Sum值。
            	m = new int[1][1];
    		    m[0] = new int[]{-1};
            }else{
             int middle = (a.length -1)/2; //取中间数,然后对数组进行左右划分。
    		 int[] left  = Arrays.copyOfRange(a, 0, middle+1);
    	     int[] right = Arrays.copyOfRange(a, middle+1, a.length);
    		 for (int i=0;i<=sum;i++){//通过for循环将Sum值得所有两步运算进行穷举。
    			int[][] la = findEqualFormula(left,i);//递归调用,直到传入的数组中只有一个元素为止
    			if (la[0][0] == -1) //如果返回{{-1}},则说明上述数组left元素无法通过加法运算得到对应的Sum值。这时,则说明当前for循环中的两步运算组合无效。忽略当前运算组合,继续下一个组合的尝试。
    				continue;
    			int[][] ra= findEqualFormula(right,sum - i);//递归调用,直到传入的数组中只有一个元素为止
                if (ra[0][0] == -1) //如果返回{{-1}},则说明上述数组right元素无法通过加法运算得到对应的Sum值。这时,则说明当前for循环中的两步运算组合无效。忽略当前运算组合,继续下一个组合的尝试。 			
    			    continue;
                int[][] ma = crossMerge(la,ra);//如果上述两个递归方法返回有效的元素组合,则将元素进行交叉合并,得出当前数组元素中可用的加法组合
                m = appendMerge(m,ma);
                valid_flag = true;
    		 }
    		 if (!valid_flag){ // 如果for循环中所有穷举的两步运算组合都不适用,则返回{{-1}}
    			 m = new int[1][1];
    			 m[0] = new int[]{-1};
    		 }
    		 
            }

        }else if (a.length == 1){
        	m = new int[1][1];
        	if (a[0] == sum) //如果分解到数组中只有一个元素时,如果与sum值相等,则是我们需要找的值。返回数组{{a[0]}}
        		m[0] = new int[]{a[0]};
        	else
        		m[0] = new int[]{-1};//如果分解到数组中只有一个元素时,如果与sum值不相等,则说明数组中的值无法通过求和得到我们的预期结果。返回数组{{-1}}
        }
        
     return m;   

	}
	
}

运行结果如下 以[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] = 20 为例


1 19 
2 18 
3 17 
1 2 17 
4 16 
1 3 16 
5 15 
1 4 15 
2 3 15 
6 14 
1 5 14 
2 4 14 
1 2 3 14 
7 13 
1 6 13 
2 5 13 
3 4 13 
1 2 4 13 
8 12 
1 7 12 
2 6 12 
3 5 12 
1 2 5 12 
1 3 4 12 
9 11 
1 8 11 
2 7 11 
3 6 11 
1 2 6 11 
4 5 11 
1 3 5 11 
2 3 4 11 
1 9 10 
2 8 10 
3 7 10 
3 8 9 
1 2 7 10 
1 2 8 9 
4 6 10 
4 7 9 
1 3 6 10 
1 3 7 9 
5 6 9 
5 7 8 
1 4 6 9 
1 4 7 8 
2 3 6 9 
2 3 7 8 
1 5 6 8 
2 4 6 8 
1 2 3 6 8 
2 5 6 7 
3 4 6 7 
1 2 4 6 7 
1 4 5 10 
2 3 5 10 
1 2 3 4 10 
2 4 5 9 
1 2 3 5 9 
3 4 5 8 
1 2 4 5 8 
1 3 4 5 7 
2 3 4 5 6 


利用分治法求一组数据的和。 利用分治法求一组数据的和。 #include<stdio.h> #include<stdlib.h> int add(int *a,int left,int right); int main() { int i,n; int *array; printf("请输入数组的大小:"); scanf("%d", &n); ar... 阅读详情

相关推荐

算法题04:分治法:求第K小元素(线性时间选择算法)

求第k小元素 题目内容: 给定一个线性序列集,要求使用分治法求出其中指定的第 KKK 小的数的值和位置,如给定 nnn 个元素和一个整数 iii,1≤i≤n1≤i≤n1≤i≤n,输出这 nnn 个元素中第 iii 小元素的值及其位置。 一、问题分析(模型、算法设计和正确性证明等) 解决第K小问题有如下几种方法 ①将n个数排序(比如快速排序或归并排序),选取排序后的第k个数,时间复杂度为O(nlog...

宇智波Akali的博客 3万+

用分治算法求一组数的和

1.解题思路 (1)将这组数等分为两组(两组数的个数可能差1),分别求这两组数的和; (2)递归分解直到每组数的元素个数<=2,可简单解决两个数以内的和问题; (3)递归出口:如果只有一个数,则直接返回这个数。 2.伪代码描述 getsum(a,i,j) { if i==j then { return a[i];} else if i==j-1 then { retu...

yo_u_niverse的博客 4449

分治法-169多数元素

分治法01——169.多数元素题目思考代码分析 今天是第一次做算法题,希望这门课能学好吧。 题目 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [3,2,3] 输出: 3 思考 虽然这道题有很多解法,但这次我只用分治策略来解决。 首先,需要理解题意。“多数元素是指在数组中出现次数大于 ⌊n/2⌋ 的元素” 那么事实上就是要找出数组出现次数过半的元素。这也就说明,它只有一

weixin_49930263的博客 1940

分治法求数组的和

分治法求数组的和

weixin_43911526的博客 3045

经典分治算法题(Java实现)

待更新

qq_42862882的博客 2234

求n个元素的全排序(从分治思想超详细解析)

概述 这是一道典型的数据结构考研题,我看目前网上大部分博主讲的都不太通俗易懂,代码质量也参差不齐,本博文将用大白话帮你理解这道典型的分治思想算法题。 1.分治思想 1.1定义 分治算法在维基百科上的定义为:在计算机科学中, 分治法是建基于多项分支递归的一种很重要的算法范式。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题...

JYplute的博客 3433

Kotlin程序员面试算法宝典【2.0】

本文介绍了查找数组元素最大值和最小值的三种方法:蛮力法(时间复杂度O(n),比较次数2n-2)、分治法(比较次数约3n/2-2)和变形的分治法(递归实现)。还讲解了如何找出旋转数组中的最小元素,提出二分查找法(最坏时间复杂度O(n))和数组旋转的实现方法。此外,介绍了寻找数组中缺失数的两种线性时间算法:累加求和法和异或法(时间复杂度均为O(n))。最后,针对找出出现奇数次的两个数的问题,给出了Hash法(空间复杂度O(n))和更优的异或法(时间复杂度O(n),空间复杂度O(1))。这些方法针对不同场景提供了

qq_43416206的博客 1136

数组运算18题:从递归求和解到Kadane算法

数组作为计算机科学中最基础的数据结构,其操作原理直接影响算法效率。递归与分治思想通过分解问题规模提升计算性能,如递归求和的时间复杂度为O(n),而分治法求极值优化至3n/2-2次比较。Kadane算法等经典解法展示了如何用O(n)时间解决最大子数组问题,这些技术在金融分析、信号处理等场景具有重要工程价值。本文通过18道经典题目,涵盖从数组求和、查找重复元素到子数组问题等核心运算场景,特别适合准备技术面试的开发者系统掌握数组处理技巧。

weixin_35364187的博客 530

【算法】LeetCode算法题-Maximum Subarray

这是悦乐书的第154次更新,第156篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第13题(顺位题号是53)。给定一个整数数组nums,找出一个最大和,此和是由数组中索引连续的元素组成,至少包含一个元素。例如: 输入:[-2, 1, -3, 4, -1, 2, 1, -5,4] 输出:6 说明:[4,-1,2,1]具有最大的和为6 输入:[1, 2, 3] 输出...

weixin_33754913的博客 102

分治方法求数组的和

【问题描述】利用分治算法对一个具有n个整数元素的数组元素求和; 【输入形式】输入两行,第一行为一个整数n,第二行为n个数组元素,n个元素中间用空格隔开。 【输出形式】输出一个整数。 【样例输入】 8 8 9 0 1 2 5 4 3 【样例输出】 32

AIGC 902

单晶塑性abaqus-umat自学

单晶塑性abaqus-umat 摘要1. 简介2. 单晶弹塑性本构模型回顾2.1运动学 本文以翻译黄永刚老师的umat文章为主,这个颜色的为个人的理解。 摘要 包含单晶塑性的abaqus用户材料子程序。本文回顾有限元形式的单晶弹塑性和黏弹塑性,包含小变形理论,以及严格的有限变形和有限旋转理论。单晶的非弹性变形由于晶体滑移,假定遵从Schmid准则。提出多种多样的分切应力与剪切变形的自硬化和潜硬化关系,并且包含在子程序内。 1. 简介   有限元程序ABAQUS已经广泛应用在固体的变形与应力分析。除了自身大量

Niklas4088的博客 1万+

分治——快速排序算法题

分治解决问题的思想就是大事化小,将一个大问题分解成若干个子问题。这道题其实就是让我们对数组进行操作,使操作之后的数组呈现出三段区间[0,left],[left+1,right-1],[right,size-1],这三个区间的元素分别都是0,1,2.既然是进行数组分块,我们就可以使用双指针的思想来解决:首先定义一个指针i;然后在分别创建两个指针和我们的目的是将数组分为三块,。

xsc2004zyj的博客 1179

用Arduino和FS-i6X遥控器,从零开始打造你的第一只仿生扑翼蝴蝶(附完整代码解析)

本文详细介绍了如何利用Arduino和FS-i6X遥控器从零开始制作仿生扑翼蝴蝶,包括硬件准备、电路连接、代码解析和调试技巧。通过完整的代码示例和参数说明,帮助读者快速掌握仿生机器人的制作要点,实现蝴蝶的自然飞行效果。

weixin_28727975的博客 309

分治——归并排序算法题

在合并阶段,我们无法在原数组进行合并,需要借助一个。

xsc2004zyj的博客 843

AD936x Evaluation Software 实战配置指南:从寄存器设置到滤波器优化

本文提供AD936x Evaluation Software的实战配置指南,详细解析从工程创建、RF向导与时钟模块配置,到数字滤波器优化、数字接口设置及增益控制的完整流程。重点分享寄存器设置、滤波器系数权衡及PLL稳定技巧等核心要点,帮助开发者高效配置AD9361/AD9363射频芯片,快速应用于SDR、基站等场景。

perl8的博客 696

强网杯Web题ezphp解题全记录:利用PHP反序列化与条件竞争拿下服务器

本文详细解析了强网杯Web题目ezphp的解题过程,通过PHP反序列化与条件竞争漏洞的组合利用,成功获取服务器权限。文章深入剖析了反序列化链的构造、文件上传绕过技巧以及条件竞争的实际应用,为CTF选手和Web安全研究者提供了宝贵的实战经验。

weixin_29006187的博客 375

经典算法题:寻找数组中第k大的元素

这算是一道相当经典的算法题了:在长度为N的乱序数组中寻找第k(n&gt;=k)大的元素。扩展思考:如何处理数组中的重复元素?比如,对于数组a={1,2,2,2,3,3,3},第二大的元素应该是3还是2呢?本文作这种分类:如果第二大的元素是3,说明在处理第k大的元素时不处理重复的数据,也就是将原数组进行降序排序后,下标为k-1的元素。这种处理方法称之为“不处理重复数据方法”;如果第二大的元素是2,说...

凛冬烈焰的博客 2万+

病理组学分析系列教程1:使用Python-histolab进行病理图像预处理,tiles切片自动生成

病理图像tiles自动生成,WSI图像预处理

qq_43449643的博客 1740

寻找数组中第k大的元素

这算是一道相当经典的算法题了: 在长度为N的乱序数组中寻找第k(n>=k)大的元素。 (1)最简单直接的方法:先排序再找 最简单直接的想法是首先进行排序。假设元素的数量不大,比如才几千个,那就可以先进行排序,比如用快排或堆排,平均时间复杂度为O(N*logN),然后取出前k个,于是总时间复杂度为O(NlogN)+O(k)=O(NlogN)。当然这种做法是浪费了不少的时间的,因为题目只要...

gcs的博客 3647

保姆级避坑指南:在Ubuntu 18.04上搞定速腾Helios雷达驱动与fast-LIO2的完整配置流程

本文提供了一份详细的速腾Helios雷达与fast-LIO2在Ubuntu 18.04上的配置避坑指南,涵盖驱动安装、数据格式转换到建图全流程。特别针对常见编译错误和数据转换问题提供了解决方案,帮助开发者高效完成环境搭建与建图任务。

weixin_27252001的博客 112

Open3d Qt的环境配置

目前统一使用qt6配置,open3d中可视化功能目前使用vtk代替,语言为c++。

阁楼 919

超详细!详解一道高频算法题:数组中的第 K 个最大元素

点击蓝色“五分钟学算法”关注我哟加个“星标”,天天中午 12:15,一起学算法作者 | 李威来源|https://www.liwei.party/整理| 五分钟学算法今天分享的题目来源于 LeetCode 第 215 号问题,是面试中的高频考题。题目描述在 未排序 的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。示例 1:输...

程序员吴师兄的博客 2331

2026华为OD面试题029:勇攀数字高峰

在给定的数字地形图里寻找登山路径,数字代表当前位置的海拔高度。要求从最低海拔出发,不断攀登,最终到达最高山峰。地图保证最低海拔和最高山峰都只有一个。 登山规则: - 路径上的海拔必须严格递增 - 只能向上下左右 4 个方向移动 - 路径必须从最低海拔开始,到最高海拔结束 - 每个地点只能走一次 - 每一步的攀登高度差必须大于 0,且不超过指定值 `K` 输出满足条件的登山路径的数量。

琅嬛福地 113

算法练习——分治_快排

分治_快排

m0_51952310的博客 974

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

算法---数组总结篇3(连续数组求和)

一、连续数组求和 Leetcode 53 最大子序和 题目描述:给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 说明:解释: 连续子数组 [4,-1,2,1] 的和最大,为6。 思路1:判断加了当前数之后,是否会使得和增大,如果不...

dili8870的博客 1266

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【算法】C++算法题总结-数组

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。示例 1:输入:nums = [5,7,7,8,8,10], target = 8输出:[3,4]示例 2:输入:nums = [5,7,7,8,8,10], target = 6输出:[-1,-1]示例 3:输入:nums = [], target = 0输出:[-1,-1]题解。

zq563100792的博客 1538
上一篇: 生产者-消费者模式 系列 之二 ReentrantLock, Condition 篇
下一篇: 一次Linux磁盘空间清理的经历
TechNerd
博客等级 码龄14年 5粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值