上回看到一道微软的算法题,题目大概是说:有一个很大的整型数组,我们怎样能够找到一个不在这个数组中的值。
假设一个数组的大小很大(比如说35000个值),我们知道整型的取值范围在某种c/c++编译器中是16位的,也就只能到65536。那么怎样才能通过最少的代价找到不在这个数组中的整型值呢?!
解答:
1、我们可以利用像数数字一样的算法,来解答这个问题。比如说我们数1到10的时候,如果1到10都是连续的话,那么我们可以肯定在这个中间是不会存在不在这个范围类的值了,具体到这个环境中,我们同样可以这样考虑,假设我们把数组遍历一遍,把其中所有能够连续的数值都去掉,那么那些连续数值中间的不连续地段,就是我们要找的值的所在。
2、因为java语言对于数据结构的良好封装,这道题的java解答很简单也容易。首先我们描述下面一个数据结构:
/*
* Created on 2003-4-6
*
* To change this generated comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package bia.arithmetic;
import java.io.PrintStream;
/**
* @author Administrator
*
* To change this generated comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class NumberNode {
int value ;
boolean hasLeft ;
boolean hasRight ;
NumberNode next,prev ;
public void print(PrintStream out){
String s = String.valueOf(value) ;
if (hasLeft){
s = "-" + s ;
}
else {
s = " " + s ;
}
if (hasRight){
s = s + "-" ;
}
else {
s = s + " " ;
}
out.print(s) ;
}
public NumberNode(){
value=0 ;
hasLeft = false ;
hasRight = false ;
}
/**
* @return boolean
*/
public boolean isHasLeft() {
return hasLeft;
}
/**
* @return boolean
*/
public boolean isHasRight() {
return hasRight;
}
/**
* @return NumberNode
*/
public NumberNode getNext() {
return next;
}
/**
* @return NumberNode
*/
public NumberNode getPrev() {
return prev;
}
/**
* @return int
*/
public int getValue() {
return value;
}
/**
* Sets the hasLeft.
* @param hasLeft The hasLeft to set
*/
public void setHasLeft(boolean hasLeft) {
this.hasLeft = hasLeft;
}
/**
* Sets the hasRight.
* @param hasRight The hasRight to set
*/
public void setHasRight(boolean hasRight) {
this.hasRight = hasRight;
}
/**
* Sets the next.
* @param next The next to set
*/
public void setNext(NumberNode next) {
this.next = next;
}
/**
* Sets the prev.
* @param prev The prev to set
*/
public void setPrev(NumberNode prev) {
this.prev = prev;
}
/**
* Sets the value.
* @param value The value to set
*/
public void setValue(int value) {
this.value = value;
}
}
然后,我们利用这个结构构造一个NumberList链表,来处理排序和依次读取的操作,在这个过程中,将中间连续的部分屏蔽掉,只留下连续的边界。
/*
* Created on 2003-4-6
*
* To change this generated comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package bia.arithmetic;
import java.io.PrintStream;
/**
* @author Administrator
*
* To change this generated comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class NumberList {
NumberNode first;
public void print(PrintStream out){
out.println("======Begin print List======") ;
NumberNode p = first ;
while (null!=p){
p.print(out) ;
p = p.getNext() ;
}
out.println("/n======End print List======") ;
}
public NumberList() {
}
public NumberNode getFirst() {
return first;
}
public void addNumber(int number){
NumberNode node = new NumberNode() ;
node.setValue(number) ;
addNode(node) ;
}
/**
* 增加一个节点的方法
* @Renzhichao
* @param node
*/
public void addNode(NumberNode node) {
if (first == null) {
first = node;
first.setPrev(null);
first.setNext(null);
first.setHasLeft(false) ;
first.setHasRight(false) ;
}
else {
NumberNode tmp = first;
NumberNode p = tmp;
while (tmp.getValue() < node.getValue() && tmp.getNext() != null) {
p = tmp;
tmp = tmp.getNext();
}
if (tmp.getValue()<node.getValue()){
//node插在链表的结尾。
tmp.setNext(node) ;
node.setPrev(tmp) ;
node.setNext(null) ;
if (tmp.getValue()+1==node.getValue()){
tmp.setHasRight(true) ;
node.setHasLeft(true) ;
if (tmp.isHasLeft()&&tmp.isHasRight()){
p.setNext(node) ;
node.setPrev(p) ;
tmp=null ;
}
}
}
else if (tmp.getValue()>node.getValue()){
//node插在链表的中央。
if (tmp==first){
//首先判断tmp是不是first
first = node ;
first.setHasLeft(false) ;
first.setHasRight(false) ;
first.setNext(tmp) ;
first.setPrev(null) ;
tmp.setPrev(node) ;
if (first.getValue()+1==tmp.getValue()){
first.setHasRight(true) ;
tmp.setHasLeft(true) ;
if (tmp.isHasLeft()&&tmp.isHasRight()){
//去掉tmp节点
first.setNext(tmp.getNext()) ;
tmp = null ;
}
}
}
else {
if (p.getValue()+2 == tmp.getValue()){
//判断是不是p和tmp可以连续了
p.setHasRight(true) ;
tmp.setHasLeft(true) ;
}
else if (!p.isHasRight()&&!tmp.isHasLeft()){
p.setNext(node) ;
tmp.setPrev(node) ;
node.setPrev(p) ;
node.setNext(tmp) ;
if (p.getValue()+1 == node.getValue()){
p.setHasRight(true) ;
node.setHasLeft(true) ;
}
else if (node.getValue()+1==tmp.getValue()){
node.setHasRight(true) ;
tmp.setHasLeft(true) ;
}
}
}
}
}
}
}