清除整数数组中任意和为0的子串并输出
输入一个整数序列. 每个项可能的取值为 正数,负数,零. 如 {1,3,4,-3,-1,9}
要求去除数列中的任意长度的和为零的子串.比如上述序列中的. 4,-3,-1
package train.interview; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * 处理思路; * 1. 先生成一个前缀和序列. * 如 S1,S2,S3,S4.....Sn,Sn+1 * 这样新的序列中如果存在两相等的值. 比如 S2=S4.那 a3+a4 = 0 * 问题转化为查找前缀和中的数组中的重复出现的sum 的数. * 这只是思路.具体细节要考虑一个值出现不只2次.比如3次的时候该如何处理. 这种 * 这里的处理是把出现的首尾连在一起作为一个0序列. * 在零序列消除后.0序列中已经擦除的数可以认为不存在.从而新形成了一个前缀和 序列.这样.就可以重复的往下. * 直到完成所有的项的检查.具体看代码 */ public class TrimZeroSubSequence { private class PrefixSumNode{ // 当前节点的值 private Integer value = null; // 当前节点的前缀和 private Integer prefixSum = null; // 当前节点的索引号 private int index = -1; // 把节点串起来的指针 // 前向指针 private PrefixSumNode prevNode = null; // 后向指针 private PrefixSumNode nextNode = null; public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public Integer getPrefixSum() { return prefixSum; } public void setPrefixSum(Integer prefixSum) { this.prefixSum = prefixSum; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public PrefixSumNode getPrevNode() { return prevNode; } public void setPrevNode(PrefixSumNode prevNode) { this.prevNode = prevNode; } public PrefixSumNode getNextNode() { return nextNode; } public void setNextNode(PrefixSumNode nextNode) { this.nextNode = nextNode; } @Override public String toString() { return "PrefixSumNode{" + "value=" + value + ", prefixSum=" + prefixSum + ", index=" + index + '}'; } } public List<Integer> filterZeroSubSequence(List<Integer> source) { if (source == null || source.isEmpty()) { return null; } if (source.size() == 1 && source.get(0) == 0) { return null; } PrefixSumNode headNode = null, tailNode = null; int curSum = 0; int curIndex = 0; // 构建前缀和双向链表: O(n) for (Integer value : source) { curSum += value; PrefixSumNode node = new PrefixSumNode(); node.setIndex(curIndex++); node.setPrefixSum(curSum); node.setValue(value); if (tailNode != null) { tailNode.setNextNode(node); node.setPrevNode(tailNode); tailNode = node; }else { headNode = node; tailNode = node; } } // 存储前缀和已经存储的值 Set<Integer> existPrefixSumSet = new HashSet<>(); // 存储前缀和与节点的 mapping 关系 Map<Integer/*preSum*/, PrefixSumNode> sum2NodeMapping = new HashMap<>(); // 大循环 O(n) * 2 PrefixSumNode iterNode = headNode; do { if (!existPrefixSumSet.contains(iterNode.prefixSum)) { System.out.println("添加不存在的节点:" + iterNode); existPrefixSumSet.add(iterNode.prefixSum); sum2NodeMapping.put(iterNode.getPrefixSum(), iterNode); System.out.println("put:" + iterNode.getPrefixSum()); } else { // 已经存在此前缀和.要进行合并清除. // 1.找出先前存在的节点 System.out.println("已经存在:"+iterNode.getPrefixSum()); PrefixSumNode existNode = sum2NodeMapping.get(iterNode.prefixSum); if (existNode == null) { System.out.println("NotExist:" + iterNode.prefixSum); return null; } try { cleanZeroSequence(existNode, iterNode, existPrefixSumSet, sum2NodeMapping); } catch (Exception e) { System.out.println(e); } } } while ((iterNode = iterNode.nextNode) != null); List<Integer> outPut = new LinkedList<>(); iterNode = headNode; do { outPut.add(iterNode.getValue()); } while ((iterNode = iterNode.nextNode) != null); return outPut; } /** * 清除两节点间的子序列 * @param existNode * @param iterNode * @param existPrefixSumSet * @param sum2NodeMapping */ private void cleanZeroSequence(PrefixSumNode existNode, PrefixSumNode iterNode, Set<Integer> existPrefixSumSet, Map<Integer, PrefixSumNode> sum2NodeMapping) { PrefixSumNode nextNode = existNode.nextNode; do { sum2NodeMapping.remove(nextNode.getPrefixSum()); existPrefixSumSet.remove(nextNode.getPrefixSum()); System.out.println("remove:" + nextNode.getPrefixSum()); } while (nextNode != iterNode && (nextNode = nextNode.nextNode) != null); // 链表中把0子序列全部清除 existNode.setNextNode(iterNode.nextNode); if (iterNode.nextNode != null) { iterNode.nextNode.prevNode = existNode; } } public static void main(String[] args) { List<Integer> list = new TrimZeroSubSequence() .filterZeroSubSequence(Arrays.asList(3, 5, -3, -1, -1, 2, 8, 9, -2, -7, 23)); System.out.println(list); } }
程序中的示例串为:
(3, 5, -3, -1, -1, 2, 8, 9, -2, -7, 23)
-------------- ---------
输出为:
[3, 2, 8, 23]