简体   繁体   English

查找三角形中的所有非素数路径

[英]Find all Non-Prime Paths in a triangle

I'm trying to find routes that do not contain prime numbers in a triangle of integers leading from top to bottom.我试图在从上到下的整数三角形中找到不包含素数的路线。

What is wrong with my code?我的代码有什么问题?

For example ( int[][] input = {{1}, {8, 4}, {2, 6, 9}, {8, 5, 9, 3}} ),例如( int[][] input = {{1}, {8, 4}, {2, 6, 9}, {8, 5, 9, 3}} ),

   1    
  8 4
 2 6 9
8 5 9 3

This triangle has three paths that meet these criteria:这个三角形有三个满足这些标准的路径:

1 - 8 - 6 - 9  
1 - 4 - 6 - 9  
1 - 4 - 9 - 9

How can I achieve this?我怎样才能做到这一点?

My code:我的代码:

private static void findPaths(int x, int y, int input[][])
{
   if(x < input.length - 1)
   {
     if(!isPrime(input[x + 1][y]) & !isPrime(input[x + 1][y + 1]))
     {
         System.out.println(input[x + 1][y]);
         findPaths(x + 1, y, input);
            
         System.out.println(input[x + 1][y + 1]);
         findPaths(x + 1, y + 1, input);
     }
     else if(!isPrime(input[x + 1][y]))
     {
         System.out.println(input[x + 1][y]);
         findPaths(x + 1, y, input);
     }
     else if(!isPrime(input[x + 1][y + 1]))
     {
         System.out.println(input[x + 1][y + 1]);
         findPaths(x + 1, y + 1, input);
     }
   }
}

public static boolean isPrime(int num)
{
  if (num <= 1) {return false;}

  for (int i = 2; i * i <= num; i++)
  {
     if ((num % i) == 0) {return false;}
  }
  return true;
}

Results for findPaths(0, 0, input) (array input initialized as shown above): findPaths(0, 0, input)的结果(数组input如上所示初始化):

8
6
9
4
6
9
9
9

This problem can be solved by modeling the relationships between the numbers in the given array as a Graph .这个问题可以通过将给定数组中的数字之间的关系建模为Graph来解决。

Note that although the elements form a structure which resembles a Binary Tree .请注意,尽管元素形成了类似于二叉树的结构。 It's certainly not a tree because each node of the tree by definition should have only one parent-node , but here it's not the case (remainder: Tree - is a particularization of a Graph, which has no circles, intersections between brunches and disjointed components).它当然不是一棵树,因为根据定义,树的每个节点都应该只有一个 parent-node ,但在这里情况并非如此(其余:树 - 是 Graph 的一种特殊化,它没有圆圈、早午餐和不相交的组件之间的交叉点)。

      1 <- root element
     / \   
    8   4 <- level
   / \ / \
  2   6   9
 / \ / \ / \
8   5   9   3

Although it's not a tree, for simplicity I would use terminology which is usually used to describe a tree, like root - which the top vertex ( node ) of this tree-like structure and level - which is a group of vertices ( nodes ) having the same depth (distance from the root to a vertex ).虽然它不是一棵树,但为简单起见,我会使用通常用于描述树的术语,如- 这种树状结构的顶部顶点( node ) 和级别- 它是一组顶点( nodes )相同的深度(从顶点的距离)。

And like in a Binary Tree , each element can be represented as a vertex having left and right children.就像在二叉树中一样,每个元素都可以表示为具有左右子节点顶点

To find all non-prime paths in a graph starting from the root , we need to traverse over the graph .要在中从开始找到所有非主路径,我们需要遍历 Each path would be represented as a separate List , ie every non-prime child of a non-prime vertex should spawn a new path .每条路径都将表示为一个单独的List ,即非素顶点的每个非素数子节点都应生成一条新路径 And every encountered prime vertex would cause the path that leads to it to be discarded.并且每个遇到的素数顶点都会导致通往它的路径被丢弃。

To traverse the implement the graph , I've implemented Depth first search algorithm using recursion (because it's relatively easier to digest).为了遍历实现,我使用递归实现了深度优先搜索算法(因为它相对更容易消化)。

We would have two base cases (conditions when recursion should terminate):我们将有两种基本情况(递归应该终止的条件):

  • a prime number has been encountered, path gets invalidated;遇到素数,路径无效;
  • we've reached the last level and current vertex has a non-prime value, current path should be added to the collection of paths .我们已经到了最后一层并且当前顶点有一个非质数当前路径应该被添加到路径集合中

And in case if current vertex has a non-prime value, and it doesn't belong to the last level (ie it has children), we need to fire the depth first search recursively for both left and right child-vertices .如果当前顶点有一个非质数,并且它不属于最后一层(即它有孩子),我们需要right left顶点递归地触发深度优先搜索 That would be the recursive case of the algorithm.那将是算法的递归情况

Note: to avoid shifting the focus from the main goal of finding non-prime paths in the Graph to checking whether a particular value is a prime number, I've used built-in method BigInteger.isProbablePrime() which expects an int argument certainty , denoting the probability of getting correct result according to the formula 1-1/2 certainty .注意:为了避免将焦点从在图中查找非素数路径的主要目标转移到检查特定值是否为素数,我使用了内置方法BigInteger.isProbablePrime() ,它需要一个int参数确定性, 表示根据公式1-1/2确定性得到正确结果的概率。 You're free to replace this check with any other logic.您可以随意用任何其他逻辑替换此检查。

Implementation might look like this:实现可能如下所示:

public class NonPrimeTriangle {
    private final Vertex root;
    
    private NonPrimeTriangle(Vertex root) {
        this.root = root;
    }
    
    public List<List<Integer>> getNonPrimePaths() {
        List<List<Integer>> paths = new ArrayList<>();
        dfs(paths, new ArrayList<>(), root);
        
        return paths;
    }
    
    private void dfs(List<List<Integer>> paths, List<Integer> path, Vertex root) {
        if (BigInteger.valueOf(root.getValue()).isProbablePrime(100)) return; // base case - a prime number has been encountered, hence this path is invalidated
        
        path.add(root.getValue());  // vertex is proved to be non-prime and should be added to the path
        
        if (root.hasNoChildren()) { // base case - a non-prime path has been encountered found
            paths.add(path);
            return;
        }
        // recursive case
        dfs(paths, new ArrayList<>(path), root.getLeft());
        dfs(paths, new ArrayList<>(path), root.getRight());
    }
    
    // Not a part of the Algorithm - convenience-method for parsing the given Array into a Graph
    public static NonPrimeTriangle parse(int[][] arr) {
        if (arr.length == 0 || arr[0].length == 0) throw new IllegalArgumentException();
        
        Vertex root = new Vertex(arr[0][0]);
        NonPrimeTriangle triangle = new NonPrimeTriangle(root);
        List<Vertex> prevLevel = List.of(root);
        
        for (int row = 1; row < arr.length; row++) {
            List<Vertex> nextLevel = new ArrayList<>(prevLevel.size() + 1); // next level of Vertices
            for (int col = 0; col < arr[row].length; col++) {
                Vertex newVertex = new Vertex(arr[row][col]);
                // every vertex has two parents, except for the leftmost and the rightmost which have only one and the root which has none
                if (col != 0) prevLevel.get(col - 1).setRight(newVertex);
                if (col != prevLevel.size()) prevLevel.get(col).setLeft(newVertex);
                
                nextLevel.add(newVertex); // updating the next level of Vertices
            }
            prevLevel = nextLevel;
        }
        return triangle;
    }

    public static class Vertex {
        private final int value;
        private Vertex left;
        private Vertex right;
    
        public Vertex(int value) {
            this.value = value;
        }
    
        public boolean hasNoChildren() {
            return left == null && right == null;
        }
        
        // getters & setters
    }
}

main()

public static void main(String[] args) {
    int[][] input = {{1}, {8, 4}, {2, 6, 9}, {8, 5, 9, 3}};
    NonPrimeTriangle triangle = NonPrimeTriangle.parse(input);
    
    triangle.getNonPrimePaths().forEach(System.out::println);
}

Output: Output:

[1, 8, 6, 9]
[1, 4, 6, 9]
[1, 4, 9, 9]

A link to Online Demo在线演示的链接

Alternative approach (don't miss comments in code):替代方法(不要错过代码中的注释):

private static void traverseNonPrimalAndPrintPaths(int row, int col, int[][] arr, String curPath){
    int curNum = arr[row][col];
    if (!isPrime(curNum)) {//we only want to handle non-prime values

        //lets add value we are in to current path
        if (row == 0){//first value shouldn't have "-" before it
            curPath = String.valueOf(curNum);
        } else {//later values need to also add "-" before them in path
            curPath = curPath + "-" + curNum;
        }

        //If there are rows below check left and right "node" below current node
        if (row < arr.length-1){//we are NOT in last row
            traverseNonPrimalAndPrintPaths(row+1, col, arr, curPath);//check left node
            traverseNonPrimalAndPrintPaths(row+1, col+1, arr, curPath);//check right node
        } else {//here we know there are no more rows.
            //So we all we need to do is print path we took to get here.
            System.out.println(curPath);
        }
    }
}

Demo:演示:

int[][] input1 = {{1}, {8, 4}, {2, 6, 9}, {8, 5, 9, 3}};
traverseNonPrimalAndPrintPaths(0, 0, input1,"");

Output: Output:

1-8-6-9
1-4-6-9
1-4-9-9

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM