简体   繁体   English

java 中的 Codility MaxPathFromTheLeftTopCorner 练习

[英]Codility MaxPathFromTheLeftTopCorner exercise in java

I'm tring to solve this https://app.codility.com/programmers/custom_challenge/technetium2019/我正在努力解决这个https://app.codility.com/programmers/custom_challenge/technetium2019/

Here is the text of the exercise:这是练习的文本:

You are given a matrix A consisting of N rows and M columns, where each cell contains a digit. Your task is to find a continuous sequence of neighbouring cells, starting in the top-left corner and ending in the bottom-right corner (going only down and right), that creates the biggest possible integer by concatenation of digits on the path. By neighbouring cells we mean cells that have exactly one common side.

    Write a function:

    class Solution { public String solution(int[][] A); }

    that, given matrix A consisting of N rows and M columns, returns a string which represents the sequence of cells that we should pick to obtain the biggest possible integer.

    For example, given the following matrix A:

    [9 9 7] [9 7 2] [6 9 5] [9 1 2]

    the function should return "997952", because you can obtain such a sequence by choosing a path as shown below:

    [9 9 *] [* 7 *] [* 9 5] [* * 2]

    Write an efficient algorithm for the following assumptions:

            N and M are integers within the range [1..1,000];
            each element of matrix A is an integer within the range [1..9].

I cannot reach 100% because I fail the case where the values of the matrix are all the same.我无法达到 100%,因为我在矩阵的值都相同的情况下失败了。

I tried to read the matrix from left to right and down as requested in the exercise but I think I misunderstood the question.我尝试按照练习中的要求从左到右并向下阅读矩阵,但我认为我误解了这个问题。

Here is my code:这是我的代码:

static String sol(int[][] A) {

    String st = "";

    int v = A.length - 1;
    int h = A[0].length - 1;
    if (h == 0) {
        for (int i = 0; i <= v; i++) {
            st = st.concat(String.valueOf(A[i][0]));
        }
    } else if (v == 0) {
        for (int i = 0; i <= h; i++) {
            st = st.concat(String.valueOf(A[0][i]));
        }

    } else {

        st = st.concat(String.valueOf(A[0][0]));

        int m = 0; //vertical
        int n = 0; // horizontal
        while(m<v && n<h) {
            if(A[m+1][n]>=A[m][n+1]){
                st = st.concat(String.valueOf(A[m+1][n]));
                m++;
            }else {
                st = st.concat(String.valueOf(A[m][n+1]));
                n++;
            }

        }

        st = st.concat(String.valueOf(A[v][h]));
    }


    return st;
}

I think I need to traverse the matrix calculating the weight of the path but I don't know how to proceed.我想我需要遍历矩阵来计算路径的权重,但我不知道如何进行。

Here I found a solution, but it seems limited to a 3x3 matrix. 在这里我找到了一个解决方案,但它似乎仅限于 3x3 矩阵。

This is my solution to the problem, but it fails last speed-tests (I get 77%).这是我对问题的解决方案,但它未能通过最后的速度测试(我得到 77%)。 Not sure if I can optimize it even more than this...不知道我是否可以优化它甚至更多...

public static String solution(int[][] A) {
    // write your code in Java SE 8

    int al = A.length;
    int all = A[0].length;

    BigInteger[][] res = new BigInteger[al+1][];
    for(int i=0; i<al+1; i++){
        res[i] = new BigInteger[all+1];
        for(int j=0; j<all+1; j++){
            res[i][j] = BigInteger.valueOf(0);
        }
    }

    for(int i=1; i<al+1; i++){
        for(int j=1; j<all+1; j++){
            res[i][j] = res[i-1][j]
                    .max(res[i][j-1])
                    .multiply(BigInteger.valueOf(10))
                    .add(BigInteger.valueOf(A[i-1][j-1]));
        }
    }

    return res[al][all].toString();

}

I tried to optimize the solution from @Bojan Vukasovic .我试图从@Bojan Vukasovic优化解决方案。 I guess it fails to get 100% due to 2 main reasons:我猜它未能获得 100% 的原因主要有两个:

  • 2-dimensional array of BigInteger allocates too much memory (I had a OOM for big input array of size 1000-by-1000). BigInteger的二维数组分配了太多的 memory(我有一个大小为 1000×1000 的大输入数组的 OOM)。 To avoid this 2-dimensional res array could be replaced by 2 1-dimensional arrays of size m (number of rows).为避免此二维res数组可以替换为大小为m (行数)的 2 个 1 维 arrays。 And the solution will look like this:解决方案将如下所示:

     static String solution(int[][] A) { final int m = A.length; final int n = A[0].length; MutableInteger[] result = new MutableInteger[m]; result[0] = new MutableInteger(A[0][0], m + n + 1); // initial raw from up to down for (int i = 1; i < m; i++) { result[i] = new MutableInteger(result[i - 1]).append(A[i][0]); } for (int j = 1; j < n; j++) { // top row we only can reach from left result[0].append(A[0][j]); // moving down for (int i = 1; i < m; i++) { MutableInteger previous = result[i - 1]; MutableInteger current = result[i]; // only replace if previous is bigger if (previous.compareTo(current) > 0) { result[i].copy(previous); } result[i].append(A[i][j]); } } return result[m - 1].toString(); }
  • Now Out Of Memory gone but 2 tests fail with a timeout.现在 Out Of Memory 消失了,但 2 个测试因超时而失败。 To fix it a new class MutableInteger with an optimized compareTo method has been introduced.为了修复它,引入了具有优化compareTo方法的新 class MutableInteger And optimized multiply by 10 + value operation.并优化multiply by 10 + value运算。 Internally it has an array of digits like BigInteger but can compare long arrays for this problem more efficiently.在内部,它有一个像BigInteger这样的数字数组,但可以更有效地比较长 arrays 来解决这个问题。 Multiplication replaced by append method.乘法替换为append方法。

     private static class MutableInteger { int[] digits; int position; int sum; int capacity; int maxIndex; private MutableInteger(int digit, int capacity) { this.digits = new int[capacity]; digits[0] = digit; sum = digit; this.capacity = capacity; position++; } private MutableInteger(MutableInteger value) { digits = value.digits.clone(); position = value.position; capacity = value.capacity; sum = value.sum; maxIndex = value.maxIndex; } private MutableInteger append(int value) { digits[position] = value; position++; sum = Math.abs(sum * 10 + value); // here integer overflow to compare exact digits efficiently return this; } private void copy(MutableInteger value) { digits = value.digits.clone(); position = value.position; capacity = value.capacity; sum = value.sum; } private int compareTo(MutableInteger other) { // optimization for long arrays comparison if (this.sum.= other.sum) { int start = Math.min(this,maxIndex. other;maxIndex); for (int i = start. i < this;position. i++) { int left = this;digits[i]. int right = other;digits[i]. if (left;= right) { other.maxIndex = i, // don't change this.maxIndex, it will be used in next iteration return Integer;compare(left; right); } } } return 0; } @Override public String toString() { StringBuilder out = new StringBuilder(position); for (int i = 0. i < position; i++) { out.append(digits[i]); } return out.toString(); } }

the class is quite simple with 2 variables for optimization. class 非常简单,有 2 个变量进行优化。 sum (2 equals arrays have the same sum value even after integer overflow) and maxIndex (used to skip comparison from beginning the arrays of digits). sum (2 等于 arrays 即使在 integer 溢出之后也具有相同的sum值)和maxIndex (用于从开始的 arrays 数字跳过比较)。

I tested this solutuion and it worked for me:我测试了这个解决方案,它对我有用:

// you can also use imports, for example:
import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public String solution(int[][] A) {
        int i = 0;
        int j = 0;

        String result = String.valueOf(A[0][0]);
        String outout = compare(i, j, A);

        return result + outout;
    }

    public String compare(int i, int j, int[][] A) {
        int h = A.length - 1;
        int v = A[0].length - 1;

        if (i == h && j == v) {
            return "";
        }

        if (j == v) {
            return A[i + 1][j] + compare(i + 1, j, A);
        }

        if (i == h) {
            return A[i][j + 1] + compare(i, j + 1, A);
        }

        if (A[i][j + 1] > A[i + 1][j]) {
            return A[i][j + 1] + compare(i, j + 1, A);
        }
        else if (A[i][j + 1] < A[i + 1][j]) {
            return A[i + 1][j] + compare(i + 1, j, A);
        } else {
            String bottom = A[i + 1][j] + compare(i + 1, j, A);
            String right = A[i][j + 1] + compare(i, j + 1, A);

            if (Integer.parseInt(bottom) > Integer.parseInt(right)) {
                return bottom;
            } else {
                return right;
            }
        }
    }
}

My solution using recursion:我使用递归的解决方案:

import java.math.BigInteger;

class Solution {
    static int[][] array;
    BigInteger selectedNumSeq = BigInteger.valueOf(0);
    int columnCount;
    int rowCount;
    int i = 0;
    public String solution(int[][] A) {
        int m = 0;
        int n = 0;
        array = A;
        columnCount = A.length; // 2
        rowCount = A[0].length; // 3
        StringBuilder startingChar = new StringBuilder(String.valueOf(array[m][n]));
        solveMe(m, n, startingChar);
        return String.valueOf(selectedNumSeq);
    }

    private void solveMe(int m, int n, StringBuilder answerItem) {
        StringBuilder currentSeq = new StringBuilder(answerItem);

        if (m +1 < columnCount) {
            int mm = m+1;
            String x = currentSeq.toString() + (array[mm][n]);
            solveMe(mm, n, new StringBuilder(x));
        }

        if (n +1 < rowCount) {
            int nn = n+1;
            String y = currentSeq.toString() + (array[m][nn]);
            solveMe(m, nn, new StringBuilder(y));
        }

        if ((n +1 == rowCount) && (m +1 == columnCount)) {
            BigInteger tempNumSeq = new BigInteger(answerItem.toString());
            if(selectedNumSeq.compareTo(tempNumSeq) < 0) {
                selectedNumSeq = tempNumSeq;
            }
        }
    }
}

Correctness: 100% (hence this will be correct for any input)正确性:100%(因此这对于任何输入都是正确的)

Here is my solution to the problem, it will fail some cases though.这是我对问题的解决方案,但在某些情况下它会失败。 I need to get more test cases to improve the algorithm.我需要获得更多的测试用例来改进算法。

 console.log(solution([[ 9, 2, 9, 3, 5 ], [ 5, 3, 9, 5, 1 ], [ 5, 6, 4, 9, 1 ], [ 4, 3, 8, 4, 5 ], [ 1, 4, 3, 5, 3 ]])); console.log(solution([[ 3, 6, 3, 8, 5, 3, 9, 8, 8, 6, 2, 4, 3, 8, 1 ], [ 5, 6, 8, 3, 3, 7, 5, 4, 4, 3, 2, 6, 9, 7, 6 ], [ 9, 2, 9, 3, 5, 9, 4, 5, 2, 9, 9, 2, 2, 5, 5 ], [ 5, 3, 9, 5, 1, 7, 1, 2, 1, 6, 8, 6, 3, 8, 8 ], [ 5, 6, 4, 9, 1, 9, 7, 8, 8, 2, 8, 6, 2, 8, 4 ], [ 4, 3, 8, 4, 5, 5, 4, 6, 9, 1, 6, 3, 6, 6, 1 ], [ 1, 4, 3, 5, 3, 8, 6, 7, 9, 5, 5, 2, 8, 1, 4 ], [ 1, 7, 9, 4, 9, 4, 6, 9, 2, 1, 2, 1, 4, 2, 1 ], [ 7, 9, 7, 9, 1, 6, 4, 3, 8, 3, 9, 4, 5, 7, 8 ], [ 7, 1, 2, 6, 3, 9, 8, 8, 4, 8, 6, 8, 3, 5, 4 ]])); console.log(solution([[ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ], [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ]])) function solution(A) { var nextindex = 0; var solution = A[0][0].toString(); for (i=0;i<A.length;i++){ var row = A[i]; for(j=0;j<row.length;j++){ var valueofright = row[nextindex+1]; var valueofnextright = row[nextindex+2]; if(i+1 < A.length){ var valueofdown = A[i+1][nextindex]; if(i+2 < A.length){ var valueofnextdown = A[i+2][nextindex]; } }else{ for (k=nextindex+1; k<row.length;k++){ solution = solution+row[k].toString(); } break; } if((valueofdown == valueofright && valueofnextright > valueofnextdown) || valueofright > valueofdown && nextindex+1 <= row.length){ solution = solution+valueofright.toString(); nextindex++; }else { solution = solution+valueofdown.toString(); break; } } } return solution; }

Explanation The algorithm tries to calculate the weight of the path by the factor of two steps.解释该算法试图通过两步的因子来计算路径的权重。

We start from the leftmost corner and check if the right value is bigger than value below the current position, and to check the path weight I also look forward to one more hoop.我们从最左角开始,检查右值是否大于当前 position 下的值,并检查路径权重我也期待多一圈。 If next hoops on right and down are equal than the decision to go down or right is made by the next consecutive numbers.如果右下和下一个篮筐等于 go 下一个或右下一个连续数字的决定。 You can improve the algorithm by adding recursive function to check if the next ones are equal until you find a different digit.您可以通过添加递归 function 来改进算法,以检查下一个是否相等,直到找到不同的数字。

My algorithm works with all the normal scenarios and also solves the problem if all the elements in the matrix are same.我的算法适用于所有正常情况,并且如果矩阵中的所有元素都相同,也可以解决问题。

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

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