Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 下面的代码何时抛出空指针异常?(也欢迎更高效的替代代码)_Java_Data Structures_Graph - Fatal编程技术网

Java 下面的代码何时抛出空指针异常?(也欢迎更高效的替代代码)

Java 下面的代码何时抛出空指针异常?(也欢迎更高效的替代代码),java,data-structures,graph,Java,Data Structures,Graph,我刚刚在foobar网站上通过了谷歌编码挑战4级考试。我的代码大部分时间都在工作,但对于我不知道的特定输入集,会抛出空指针异常。如果有人对解决拼图编码问题感兴趣,您能帮我找到以下解决方案以空指针异常结尾的输入吗?当我的代码未能达到良好的编码规范或整个替代的简单而高效的解决方案时,我也欢迎大家对我的代码发表评论。感谢(PS-希望我没有违反任何规则和分享谷歌编码挑战中提出的以下问题) 问题陈述- 根据各组兔子的起始房间号、逃生舱的房间号,以及在两条走廊之间的每个方向上一次可以容纳多少只兔子,计算出在

我刚刚在foobar网站上通过了谷歌编码挑战4级考试。我的代码大部分时间都在工作,但对于我不知道的特定输入集,会抛出空指针异常。如果有人对解决拼图编码问题感兴趣,您能帮我找到以下解决方案以空指针异常结尾的输入吗?当我的代码未能达到良好的编码规范或整个替代的简单而高效的解决方案时,我也欢迎大家对我的代码发表评论。感谢(PS-希望我没有违反任何规则和分享谷歌编码挑战中提出的以下问题)

问题陈述- 根据各组兔子的起始房间号、逃生舱的房间号,以及在两条走廊之间的每个方向上一次可以容纳多少只兔子,计算出在高峰期一次有多少只兔子可以安全到达逃生舱。 编写一个函数答案(入口、出口、路径),其中包含一个整数数组,表示聚集的兔子群在哪里,一个整数数组表示逃生舱在哪里,以及一个走廊整数数组,以整数形式返回每个时间步可以通过的兔子总数。入口和出口是不相交的,因此永远不会重叠。路径元素path[A][B]=C描述了从A到B的走廊在每个时间步都可以容纳C个兔子。走廊连接的房间最多有50间,一次最多可容纳200万只兔子

例如,如果您有:

entrances = [0, 1],
exits = [4, 5], 
path = [,  
# Room 0: Bunnies,           [0, 0, 4, 6, 0, 0],  
# Room 1: Bunnies,           [0, 0, 5, 2, 0, 0],  
# Room 2: Intermediate room, [0, 0, 0, 0, 4, 4],  
# Room 3: Intermediate room  [0, 0, 0, 0, 6, 6],  
# Room 4: Escape pods,       [0, 0, 0, 0, 0, 0],  
# Room 5: Escape pods        [0, 0, 0, 0, 0, 0]
]
然后,在每个时间步骤中,可能会发生以下情况:

0 sends 4/4 bunnies to 2 and 6/6 bunnies to 3
1 sends 4/5 bunnies to 2 and 2/2 bunnies to 3
2 sends 4/4 bunnies to 4 and 4/4 bunnies to 5
3 sends 4/6 bunnies to 4 and 4/6 bunnies to 5
因此,总共有16只兔子可以在每一个时间步的4和5点到达逃生舱。(请注意,在本例中,房间3可以将8只兔子的任何变化发送到4和5,例如2/6和6/6,但最终答案保持不变。)

测试用例

Inputs:entrances = [0], exits = [3], path = [[0, 7, 0, 0], [0, 0, 6, 0], [0, 0, 0, 8], [9, 0, 0, 0]] then Output:6

Inputs:entrances = [0, 1], exits = [4, 5], path = [[0, 0, 4, 6, 0, 0], [0, 0, 5, 2, 0, 0], [0, 0, 0, 0, 4, 4], [0, 0, 0, 0, 6, 6], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]  Output: 16
我的解决方案:

public class Answer {
    public static void main(String[] args) {
        //input 1
        int[] entrances = {0, 1};
        int[] exits = {4, 5};
        int[][] path = {{1, 0, 4, 6, 0, 0},
                {0, 1, 5, 2, 0, 0},
                {0, 0, 1, 0, 4, 4},
                {0, 0, 0, 1, 6, 6},
                {0, 0, 0, 0, 1, 0},
                {0, 0, 0, 0, 0, 1}};
        System.out.println("*****************************************for input 1:"+answer(entrances, exits, path));
        //input 2
        entrances = new int[]{0};
        exits = new int[]{3};
        path = new int[][]{ {0, 7, 0, 0},
                {0, 0, 6, 0},
                {0, 0, 0, 8},
                {9, 0, 0, 0} };
        System.out.println("*****************************************for input 2:"+answer(entrances, exits, path));
        //input with loop 1
        entrances = new int[]{0,2};
        exits = new int[]{4};
        path = new int[][]{ {0, 3, 0, 0, 0},
                {0, 0, 2, 0, 5},
                {0, 0, 0, 4, 0},
                {0, 6, 0, 0, 0},
                {0, 0, 0, 0, 0} };
        System.out.println("*****************************************for input 3:"+answer(entrances, exits, path));
        //input with loop 2
        entrances = new int[]{0,1};
        exits = new int[]{4,5};
        path = new int[][]{ {0, 0, 10, 0, 0, 0},
                            {0, 0, 0, 8, 0, 0},
                            {0, 0, 0, 4, 6, 0},
                            {0, 0, 4, 0, 0, 12},
                            {0, 0, 0, 0, 0, 0},
                            {0, 0, 0, 0, 0, 0}};
        System.out.println("*****************************************for input 4:"+answer(entrances, exits, path));

        entrances = new int[]{0};
        exits = new int[]{0};
        path = new int[][]{ {0} };
        System.out.println("*****************************************for input 5:"+answer(entrances, exits, path));
    }

    public static final int SOME_BIG_VALUE = 2146999999;

    public static int answer(int[] entrances, int[] exits, int[][] path) {
        if (path == null || entrances == null || exits == null){
            return 0;
        }
        if(path.length<2 || entrances.length<1 || exits.length<1){
            return 0;
        }
        //below makes difference with one test case
        for (int i = 0; i < path.length; i++) {
            for (int j = 0; j <path[i].length ; j++) {
                if(i==j)
                    path[i][j]=0;
            }
        }
        //creating all nodes
        ArrayList<Node> nodes = new ArrayList<>();
        for (int i = 0; i < path.length; i++) {
            nodes.add(new Node(i));
        }
        Node.constructGraph(path, nodes);

        int total = 0;
        for(int src:entrances) {
            //System.out.println("for src: "+ src);
            Node start = nodes.get(src);
            int pathCapacity = 0;
            do {
                if(start.discard)
                    break;
                pathCapacity = findCapacityOfLoopLessPath(src, exits, nodes);
                total = total + pathCapacity;
            } while (pathCapacity != 0);
        }
        return total;
    }

    /**
     *Returns >0 if valid path is found between src and one of the exits
     * Returns  0 if valid path is not found between src and any of exits
     * Apart, below function   *overcomes the loop while finding the path
     *alters graph as new paths are  discovered
     *removes dead-end path frm src to non-exit
     */
    public static int findCapacityOfLoopLessPath(int src, int[] exits, ArrayList<Node> nodes) {
        ArrayList<Node> path = new ArrayList<>();
        Stack<Node> stack = new Stack<>();
        Node start = nodes.get(src);
        stack.push(start);

        boolean reachedExit = modifiedDFS(path, stack, exits);
        int smallestCorridorSizeInPath = 0;
        if(!reachedExit){
            return smallestCorridorSizeInPath;
        }
        else{
            smallestCorridorSizeInPath = findSmallestCorridorSizeInPath(path);
            if(smallestCorridorSizeInPath != SOME_BIG_VALUE) {
                reduceCorridorSizeInPath(path, smallestCorridorSizeInPath, exits);
                return smallestCorridorSizeInPath;
            }
        }
        return smallestCorridorSizeInPath;
    }

    /**
     * Does dfs until one of the exit is reached
     * Parallelly putting nodes into path as they get discovered to reach the one of exits
     */
    private static boolean modifiedDFS(ArrayList<Node> path, Stack<Node> stack, int[] exits) {
        while(!stack.empty()) {
            Node current = stack.pop();
            if(Node.isNodeInPath(current, path)) {
                return modifiedDFS(path,stack,exits);
            }else {
                path.add(current);
            }
            if(isNodeOneOfExits(current,exits)) {
                return true;
            }
            HashMap<Node, Integer> corridorWeightToReachNextNode = current.getCorridorWeightToReachNextNode();
            for(Node node:corridorWeightToReachNextNode.keySet()) {
                if(!stack.contains(node) && !node.discard)
                    stack.push(node);
            }
        }
        return false;
    }

    public static int findSmallestCorridorSizeInPath(ArrayList<Node> path) {
        if(path.size() < 2){
            return 0;//may be if exception is thrown then we can debug more easily
        }
        int smallestCorridorSizeInPath = SOME_BIG_VALUE;

        //System.out.print("path : ");
        for (int j = 0; j <path.size() ; j++) {
            //System.out.print(path.get(j).toString()+", ");
        }

        int i;
        for (i = 0; i < path.size()-1; i++) {
            Node currentNode = path.get(i);
            Node nextNode = path.get(i+1);
            HashMap<Node, Integer> corridorWeightToReachNextNode = currentNode.getCorridorWeightToReachNextNode();
            if(corridorWeightToReachNextNode.get(nextNode)<smallestCorridorSizeInPath) {
                smallestCorridorSizeInPath = corridorWeightToReachNextNode.get(nextNode);
            }
        }
        //System.out.println("shortest corridor size in the path:" + smallestCorridorSizeInPath);
        return smallestCorridorSizeInPath;
    }

    /**
     * reduce corridor size of each in path by smallestCorridorSizeInPath
     * Removes the corresponding path with that smallest size from the graph
     * by removing respective node with smallestCorridorSizeInPath from  corridorWeightToReachNextNode
     * Also, makes node.discard = true if node's nextNode list is empty
     */
    public static void reduceCorridorSizeInPath(ArrayList<Node> path, int smallestCorridorSizeInPath, int[] exits) {
        if(path == null || exits == null){
            return;
        }
        if(path.size()<2 && exits.length==0)
            return;
        for (int i = 0; i < path.size()-1 ; i++) {
            Node currentNode = path.get(i);
            Node nextNode = path.get(i+1);
            if(currentNode==null || nextNode==null){
                return;
            }
            HashMap<Node, Integer> corridorWeightToReachNextNode = currentNode.getCorridorWeightToReachNextNode();
            if(corridorWeightToReachNextNode==null || corridorWeightToReachNextNode.size()==0) {
                return;
            }
            if(corridorWeightToReachNextNode.get(nextNode)==null) {
                return;
            }
            int currentCorridorSize = 0;
            currentCorridorSize = corridorWeightToReachNextNode.get(nextNode);
            if(currentCorridorSize==0 || currentCorridorSize == SOME_BIG_VALUE){
                return;
            }

            corridorWeightToReachNextNode.put(nextNode, (currentCorridorSize-smallestCorridorSizeInPath));
            if(currentCorridorSize == smallestCorridorSizeInPath) {
                corridorWeightToReachNextNode.remove(nextNode);
                if(corridorWeightToReachNextNode.size()==0 && !isNodeOneOfExits(currentNode,exits)) {
                    currentNode.discard = true;
                    //System.out.println("discarded node:"+ currentNode.toString());
                }
            }
        }
    }

    public static boolean isNodeOneOfExits(Node node, int[] exits) {
        for (int i = 0; i < exits.length; i++) {
            if(node.getIndex() == exits[i])
                return true;
        }
        return false;
    }}

    class Node {
    int index;
    HashMap<Node, Integer> corridorWeightToReachNextNode = null;
    Boolean discard = false;
    public Node(int index) {
        this.index = index;
        corridorWeightToReachNextNode = new HashMap<>();
    }
    public int getIndex() {
        return index;
    }

    public HashMap<Node, Integer> getCorridorWeightToReachNextNode() {
        return corridorWeightToReachNextNode;
    }

    public static Node constructGraph(int[][] matrix, List<Node> nodes) {
        for(int i = 0; i < matrix.length; i++) {
            Node currentNode = nodes.get(i);
            for(int j=0; j<matrix[i].length; j++) {
                if(matrix[i][j] != 0) {
                    Node nextNode = nodes.get(j);
                    currentNode.corridorWeightToReachNextNode.put(nextNode,matrix[i][j]);
                }
            }
        }
        return nodes.get(0);
    }

    @Override
    public boolean equals(Object obj) {
        Node node = (Node)obj;
        if(node.index == this.index)
            return true;
        return false;
    }
    @Override
    public int hashCode() {
        return index % 2;
    }

    @Override
    public String toString() {
        return Integer.toString(this.index);
    }

    public static boolean isNodeInPath(Node n, ArrayList<Node> path) {
        if(path == null || n == null) {
            return false;
        }
        boolean alreadyInPath = false;
        for( Node nodeInPath : path) {
            if(nodeInPath.equals(n))
                return true;
        }
        return false;
    }
}
公共类答案{
公共静态void main(字符串[]args){
//输入1
int[]入口={0,1};
int[]exits={4,5};
int[]path={{{1,0,4,6,0,0},
{0, 1, 5, 2, 0, 0},
{0, 0, 1, 0, 4, 4},
{0, 0, 0, 1, 6, 6},
{0, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 1}};
System.out.println(“******************************************************输入1:”+回答(入口、出口、路径));
//输入2
入口=新的int[]{0};
exits=newint[]{3};
path=newint[][{{0,7,0,0},
{0, 0, 6, 0},
{0, 0, 0, 8},
{9, 0, 0, 0} };
System.out.println(“*********************************************************用于输入2:”+回答(入口、出口、路径));
//带循环1的输入
入口=新的int[]{0,2};
exits=newint[]{4};
path=newint[][{{0,3,0,0,0},
{0, 0, 2, 0, 5},
{0, 0, 0, 4, 0},
{0, 6, 0, 0, 0},
{0, 0, 0, 0, 0} };
System.out.println(“*********************************************************输入3:”+回答(入口、出口、路径));
//带回路2的输入
入口=新的int[]{0,1};
exits=newint[]{4,5};
path=newint[][{{0,0,10,0,0,0},
{0, 0, 0, 8, 0, 0},
{0, 0, 0, 4, 6, 0},
{0, 0, 4, 0, 0, 12},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0}};
System.out.println(“*********************************************************输入4:”+回答(入口、出口、路径));
入口=新的int[]{0};
exits=newint[]{0};
path=newint[][{0}};
System.out.println(“*********************************************************输入5:”+回答(入口、出口、路径));
}
公共静态final int SOME_BIG_VALUE=214699999;
公共静态int应答(int[]入口,int[]出口,int[]path){
如果(路径==null | |入口==null | |出口==null){
返回0;
}

如果(path.length您的问题:您构建的路径包含没有出口的节点

以下示例(通过随机抽样发现):

可视化(使用graphonline.ru创建)

您的代码从(仅)开始进入节点。它按遭遇顺序将所有子节点添加到路径中。然后它探索每个子节点并将其子节点添加到路径中。最后,在评估之前,这会给出路径
0->1->2->3
,这显然是错误的。唯一正确的路径是
0->2->3
,如图所示。
在对路径求值期间,查询节点
1
s的节点
2
的邻接向量。这就是发生NullPointerException的地方


我用于生成随机样本的代码(生成1000个样本,具有可复制的结果和一个入口/出口节点)

//我的随机样本
随机数=新随机数(0升);
int路径大小=4;
对于(int i=0;i<1000;i++){
入口=新的int[]{0};
//数组.setAll(入口,j->random.nextInt(0+1));
exits=newint[]{pathSize-1};
//setAll(出口,j->random.nextInt(路径大小));
路径=新的整数[pathSize][pathSize];
setAll(path,j->IntStream.generate(()->random.nextInt(20)).limit(path size.toArray());
对于(int j=0;jentrances = {0};
exits = {3};
path = {{0, 17, 6, 0}, 
        {0, 0, 0, 0}, 
        {0, 0, 0, 9},
        {16, 0, 0, 0}};
// My random samples
Random random = new Random(0L);

int pathSize = 4;

for (int i = 0; i < 1000; i++) {
    entrances = new int[]{0};
    //Arrays.setAll(entrances, j -> random.nextInt(0+1));

    exits = new int[]{pathSize - 1};
    //Arrays.setAll(exits, j -> random.nextInt(pathSize));

    path = new int[pathSize][pathSize];
    Arrays.setAll(path, j -> IntStream.generate(() -> random.nextInt(20)).limit(pathSize).toArray());

    for (int j = 0; j < path.length; j++) {
        path[j][j] = 0;
    }

    for (int j = 0; j < path.length; j++) {
        for (int k = 0; k < path[j].length; k++) {
            path[j][k] = random.nextDouble() < 0.75 ? 0 : path[j][k];
        }
    }

    try {
        answer(entrances, exits, path);
    } catch (Exception e) {
        System.err.println("[" + String.format("%02d", i) + "] Threw an exception for inputs " + Arrays.toString(entrances) + ", " + Arrays.toString(exits) + ", " + Arrays.deepToString(path));
        e.printStackTrace();
    }
}
//below makes difference with one test case
for (int i = 0; i < path.length; i++) {
    for (int j = 0; j < path[i].length; j++) {
        if (i == j)
            path[i][j] = 0;
    }
}