清除整数数组中任意和为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]

浙公网安备 33010602011771号