算法题: 求一个整数数组中,通过元素加减运算得到指定结果的所有运算过程. 例如【5,4,6,7,1】= 9 ?
2013-07-04 19:04
696 查看
题目: 给定一个整数数组int[] a (a.length > 1),和一个整数值 m,试输出所有运算结果等于m的运算过程。可使用的运算方式只有加法和减法。数组元素最多参与一次运算。例如,给定数组【5,4,6,7,1】和整数9,输出运算结果为9的运算过程如下:
+5+4=9
+5+4+6-7+1=9
+5+4-6+7-1=9
+5-4+7+1=9
+4+6-1=9
-4+6+7=9
-5+6+7+1=9
这个题目,我们可以使用回溯算法得到所有的解。回溯法在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树中的任一节点时,先判断该节点是否包含问题的解。如果不包含,则跳过对已该结点为根的子数的搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先策略搜索。回溯法求问题所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。回溯法求问题的一个解时,只要搜索到问题的一个解就可结束。
回溯法通常包含3个步骤
针对所给问题,定义问题的解空间
确定易于搜索的解空间结构。常见的结构一般为n叉树结构,而且一般都是满n叉树。
以深度优先方式搜索解空间,并在搜索过程中使用剪枝函数避免无效搜索。深度优先策略可以选择先序遍历,中序遍历,和后序遍历。
对于给定的这个题目,我们首先要确定问题的解空间。由于如下的条件限定
运算过程只能使用加法和减法
数组元素最多参与一次运算
我们可以把数组元素的操作转换为 (x1 * +1 ) + (x2 * -1) + (x3 * 0) ....... = ? ,以题目为例, 很容易看出题目需要的解向量为 { (1,1,1,-1,1), (-1,0,1,1,1)..... } ,然后我们可以确定出解空间结构为一个3叉树,而且是一个满三叉树。三叉树深度是给定数组的长度加一,如题中数组长度为5,那么解空间结构的三叉树的深度为6。由于篇幅限制,这里只画了最左部分节点的结构。
最后,剩下的步骤就是遍历这颗三叉树,检查每个节点的结果是否符合要求。我们以根节点,左子树,中子树,和右子树的顺序进行深度优先遍历。那么以最左边树为例,其遍历的结果如上图所示,其中只有遍历到第三层时的加法运算组合满足要求 (5+4 = 9),那么我们可以得到一个解向量,即 { (1,1,0,0,0) }。另外,符合要求的解,很有可能在叶子结点获得。例如(5+4+6-7+1=9),对应的解向量为{ (1,1,1,-1,1 ) }。
代码如下
解空间数据结构的节点类
如下类为解空间数据结构,包含回溯算法的应用。
+5+4=9
+5+4+6-7+1=9
+5+4-6+7-1=9
+5-4+7+1=9
+4+6-1=9
-4+6+7=9
-5+6+7+1=9
这个题目,我们可以使用回溯算法得到所有的解。回溯法在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树中的任一节点时,先判断该节点是否包含问题的解。如果不包含,则跳过对已该结点为根的子数的搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先策略搜索。回溯法求问题所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。回溯法求问题的一个解时,只要搜索到问题的一个解就可结束。
回溯法通常包含3个步骤
针对所给问题,定义问题的解空间
确定易于搜索的解空间结构。常见的结构一般为n叉树结构,而且一般都是满n叉树。
以深度优先方式搜索解空间,并在搜索过程中使用剪枝函数避免无效搜索。深度优先策略可以选择先序遍历,中序遍历,和后序遍历。
对于给定的这个题目,我们首先要确定问题的解空间。由于如下的条件限定
运算过程只能使用加法和减法
数组元素最多参与一次运算
我们可以把数组元素的操作转换为 (x1 * +1 ) + (x2 * -1) + (x3 * 0) ....... = ? ,以题目为例, 很容易看出题目需要的解向量为 { (1,1,1,-1,1), (-1,0,1,1,1)..... } ,然后我们可以确定出解空间结构为一个3叉树,而且是一个满三叉树。三叉树深度是给定数组的长度加一,如题中数组长度为5,那么解空间结构的三叉树的深度为6。由于篇幅限制,这里只画了最左部分节点的结构。
最后,剩下的步骤就是遍历这颗三叉树,检查每个节点的结果是否符合要求。我们以根节点,左子树,中子树,和右子树的顺序进行深度优先遍历。那么以最左边树为例,其遍历的结果如上图所示,其中只有遍历到第三层时的加法运算组合满足要求 (5+4 = 9),那么我们可以得到一个解向量,即 { (1,1,0,0,0) }。另外,符合要求的解,很有可能在叶子结点获得。例如(5+4+6-7+1=9),对应的解向量为{ (1,1,1,-1,1 ) }。
代码如下
解空间数据结构的节点类
package com.csdn.blog.TechNerd.TraceBack; /* * 构造树节点,包含左子节点,中子节点,和右子节点的引用。以及该节点深度及数据信息。 */ public class Node { private Node _lnode; private Node _rnode; private Node _mnode; private int _data; private int _depth; public Node(int data,int depth){ this._data = data; this._depth = depth; } public void setLNode(Node lnode){ this._lnode = lnode; } public void setMNode(Node mnode){ this._mnode = mnode; } public void setRNode(Node rnode){ this._rnode = rnode; } public int getData(){ return this._data; } public int getDepth(){ return this._depth; } public Node getLNode(){ return this._lnode; } public Node getMNode(){ return this._mnode; } public Node getRNode(){ return this._rnode; } }
如下类为解空间数据结构,包含回溯算法的应用。
package com.csdn.blog.TechNerd.TraceBack; public class TraceBackTree { private Node _root; private int _depth; private int[] _a; private int _m; public TraceBackTree(Node root,int depth,int[] a,int m){ this._root = root; this._depth = depth; buildBTree(); this._a = a; this._m = m; } /* * 构建解空间数据结构,题目所需要的是一个满三叉树。 */ private void buildBTree(){ this._root.setLNode(createNode(1,2)); this._root.setMNode(createNode(0,2)); this._root.setRNode(createNode(-1,2)); } private Node createNode(int data,int depth){ if (depth <= this._depth){ Node n = new Node(data,depth); n.setLNode(createNode(1,depth + 1)); n.setMNode(createNode(0,depth + 1)); n.setRNode(createNode(-1,depth +1)); return n; }else{ return null; } } /* * 按照根节点,左子节点,中子节点,右子节点的顺序对数进行遍历,打印所有节点。 */ public void preOrderTraverse(){ preOrderTraverse(this._root); } private void preOrderTraverse(Node n){ if (n != null){ printNode(n); preOrderTraverse(n.getLNode()); preOrderTraverse(n.getMNode()); preOrderTraverse(n.getRNode()); } } private void printNode(Node n){ System.out.print(n.getData() + " "); } /* *回溯法求所有解。 */ public void backTrace(int[] a,int m){ int[] x = new int[this._depth - 1]; //定义存储解向量的数组。该数组长度与题目给定的数组长度相等。 backTrace(this._root,x); } private void backTrace(Node n,int[] x){ if (n.getDepth() > 1) x[n.getDepth() - 2] = n.getData(); //将节点值付给解向量数组。 if (constraints(x,n.getDepth() - 2)){ printSolution(x,n.getDepth() - 2); } if (n.getLNode() != null) backTrace(n.getLNode(),x); if (n.getMNode() != null) backTrace(n.getMNode(),x); if (n.getRNode() != null) backTrace(n.getRNode(),x); } /* * 检查目前解向量是否满足题目要求,就和等于指定值。 */ private boolean constraints(int[] x,int boundary) { int sum = 0; for (int i=0;i<= boundary;i++){ sum += _a[i] * x[i]; } return (sum == _m && x[boundary] != 0); } private void printSolution(int[] x,int boundary) { for (int i =0;i<= boundary;i++){ if (x[i] == 1){ System.out.print("+"+ _a[i]); }else if (x[i] == 0){ }else if (x[i] == -1){ System.out.print("-" + _a[i]); } } System.out.println("=" + this._m); } public static void main(String[] args){ int[] a = {5,4,6,7,1}; int m = 9; //创建的数的深度为给定数组的长度加一 TraceBackTree bt = new TraceBackTree(new Node(1,1),a.length + 1,a,m); //按照根节点,左子节点,中子节点,右子节点的顺序对数进行遍历,打印所有节点。 // bt.preOrderTraverse(); bt.backTrace(a,m); } }
相关文章推荐
- 算法题: 求一个整数数组中,通过元素加减运算得到指定结果的所有运算过程. 例如【5,4,6,7,1】= 9 ?
- 算法题: 求一个整数数组中,通过元素加减运算得到指定结果的所有运算过程. 例如【5,4,6,7,1】= 9 ?
- 对一个5位数的任意整数,求出其降序数。例如,整数是82319,则其降序数是98321。算法提示:将整数的各位数分解到一维整型数组a中,再将a数组中的元素按降序排序,最后输出a数组元素值。
- 输入一个整数数组,返回所有元素两两之差绝对值最小的值,O(n)算法
- 设计一个算法找到数组中两个元素相加等于指定数的所有组合
- 算法习题45:对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一;;;一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值
- 假如一个数组存储了一个股票,在一天交易窗口内各时间点的股票价格(正整数),只允许一次买入和一次卖出,请提供一个算法,计算出通过买入和卖出可以得到的最大利润
- 假如一个数组存储了一个股票,在一天交易窗口内各时间点的股票价格(正整数),只允许一次买入和一次卖出,请提供一个算法,计算出通过买入和卖出可以得到的最大利润
- [面试题]设计一个算法找到数组中两个元素相加等于指定数的所有组合
- [面试题]设计一个算法找到数组中两个元素相加等于指定数的所有组合
- 程序员面试金典——解题总结: 9.17中等难题 17.12设计一个算法,找出数组中两数之和为指定值的所有整数对。
- 对于一个有序数组,我们通常采用二分查找的方式来定位某一元素,请编写二分查找的算法,在数组中查找指定元素。 给定一个整数数组A及它的大小n,同时给定要查找的元素val,请返回它在数组中的位置(从0开始),若不存在该元素,返回-1。若该元素出现多次,请返回第一次出现的位置。
- java—数组乘积输入: 一个长度为n的整数数组input 输出: 一个长度为n的数组result,满足result[i] = input数组中,除了input[i] 之外的所有数的乘积,不用考虑溢出例如 input {2, 3, 4, 5} output: {60, 40, 30, 24}
- 一道值得深思的面试题:写一个函数,返回一个数组中所有元素被第一个元素除的结果。
- 通过键盘输入100以内正整数的加、减运算式,请编写一个程序输出运算结果字符串。
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右),某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
- 现在,有两个整数A和B,例如A是345,B是478,现在,需要把B插入到A里, 而A有三位,所以有四个位置选择,所得结果分别是: 478345, 347845, 344785, 345478 我们通过对比可以知道,在这当中最小的一个是344785
- 设一个长度为10的整型数组, 0)要求每个元素的值通过scanf输入,输入完成后, 1)请顺序输出这些整数, 2)请倒序输出这些整数, 3)输出这些数中的最大值, 4)输出这些数中的最小值
- 整型数组处理算法(三)把一个数组里的所有元素,插入到另一个数组的指定位置
- 输入整形数组,数组里有正数也有负数,数组中一个或连续的多个整数组成数组的子数组,求所有子数组中和的最大值 ,例如输入的数组为{1,-2,3,10,-4,7,2,-5}和最大的子数组为{3,10,