Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.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_Micro Optimization - Fatal编程技术网

Java 是否有任何有效的微优化来找到唯一网格路径的数量?

Java 是否有任何有效的微优化来找到唯一网格路径的数量?,java,micro-optimization,Java,Micro Optimization,我正在尝试解决此CSES问题:。给您一个长度为48的字符串,您必须找到路径的数量,以便遍历所有网格并在左下角结束 我相信我已经尽我最大的能力删减了搜索,正如这本书所说:(查看删减搜索类别),针对这类问题的最佳优化是防止您的路径关闭自己,我已经实现了这一点。这个特定问题的时间限制很紧,虽然我已经基本解决了这个问题,但我仍然没有通过1-2个测试用例,因为我的解决方案需要1.01秒,而不是低于1秒的时间限制 最后,我只是想知道是否有一些很酷的微优化可以用来稍微提高java代码的速度,这样我就可以通过这

我正在尝试解决此CSES问题:。给您一个长度为48的字符串,您必须找到路径的数量,以便遍历所有网格并在左下角结束

我相信我已经尽我最大的能力删减了搜索,正如这本书所说:(查看删减搜索类别),针对这类问题的最佳优化是防止您的路径关闭自己,我已经实现了这一点。这个特定问题的时间限制很紧,虽然我已经基本解决了这个问题,但我仍然没有通过1-2个测试用例,因为我的解决方案需要1.01秒,而不是低于1秒的时间限制

最后,我只是想知道是否有一些很酷的微优化可以用来稍微提高java代码的速度,这样我就可以通过这个问题的所有测试用例

import java.io.*;

public class GridPaths {
    public static class FastIO {
        InputStream dis;
        byte[] buffer = new byte[1 << 17];
        int pointer = 0;

        public FastIO(String fileName) throws Exception {
            dis = new FileInputStream(fileName);
        }

        public FastIO(InputStream is) {
            dis = is;
        }

        int nextInt() throws Exception {
            int ret = 0;
            byte b;
            do {
                b = nextByte();
            } while (b <= ' ');
            boolean negative = false;
            if (b == '-') {
                negative = true;
                b = nextByte();
            }
            while (b >= '0' && b <= '9') {
                ret = 10 * ret + b - '0';
                b = nextByte();
            }
            return (negative) ? -ret : ret;
        }

        long nextLong() throws Exception {
            long ret = 0;
            byte b;
            do {
                b = nextByte();
            } while (b <= ' ');
            boolean negative = false;
            if (b == '-') {
                negative = true;
                b = nextByte();
            }
            while (b >= '0' && b <= '9') {
                ret = 10 * ret + b - '0';
                b = nextByte();
            }
            return (negative) ? -ret : ret;
        }

        Integer[] readArray(int n) throws Exception {
            Integer[] a = new Integer[n];
            for (int i = 0; i < n; i++) a[i] = nextInt();
            return a;
        }

        byte nextByte() throws Exception {
            if (pointer == buffer.length) {
                dis.read(buffer, 0, buffer.length);
                pointer = 0;
            }
            return buffer[pointer++];
        }

        String next() throws Exception {
            StringBuilder ret = new StringBuilder();
            byte b;
            do {
                b = nextByte();
            } while (b <= ' ');
            while (b > ' ') {
                ret.appendCodePoint(b);
                b = nextByte();
            }
            return ret.toString();
        }
    }

    static char[] board;
    static boolean[][] visited = new boolean[7][7];
    static int ans = 0;

    public static boolean works(int i, int j) {
        //makes sure that current spot is on the 7x7 grid and is not visited
        return (i >= 0 && i<=6 && j>=0 && j<=6 && !visited[i][j]);
    }
    public static void solve(int i, int j, int steps) {
        if (i == 6 && j == 0) {
            if (steps == 48) ans++; //all spots of the grid have to be visited in order to be counted as part of the answer
            return;
        }
        visited[i][j] = true;
        //you are given ? characters in the input string, and those mean that you have to try out all 4 combinations (U,D,L,R)
        if (board[steps] == '?' || board[steps] == 'L') {
            //second condition of the second if statement checks if the spot directly ahead of the current spot is blocked, and if it is, the left and right spots cannot both be unvisited or else you will not continue searching 
            if (works(i,j-1) && !(!works(i,j-2) && works(i+1,j-1) && works(i-1,j-1))) {
                solve(i, j - 1, steps + 1);
            }
        }
        if (board[steps] == '?' || board[steps] == 'R') {
            if (works(i,j+1) && !(!works(i,j+2) && works(i+1,j+1) && works(i-1,j+1))) {
                solve(i, j + 1, steps + 1);
            }
        }
        if (board[steps] == '?' || board[steps] == 'U') {
            if (works(i-1,j) && !(!works(i-2,j) && works(i-1,j+1) && works(i-1,j-1))) {
                solve(i - 1, j, steps + 1);
            }
        }
        if (board[steps] == '?' || board[steps] == 'D') {
            if (works(i+1,j) && !(!works(i+2,j) && works(i+1,j+1) && works(i+1,j-1))) {
                solve(i + 1, j, steps + 1);
            }
        }
        visited[i][j] = false;

    }
    public static void main(String[] args) throws Exception {
        FastIO in = new FastIO(System.in);
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        board = in.next().toCharArray();
        solve(0,0,0);
        out.println(ans);

        out.close();
    }

}
import java.io.*;
公共类网格路径{
公共静态类禁食{
输入流dis;

byte[]buffer=new byte[1我一直在研究这个问题。除了使用标准机制读取输入文件(我在一篇评论中建议),您还可以通过做两件事在搜索alg本身中获得一点时间:

  • 将案例
    board[steps]=='?'
    与其他案例分开。因此,首先检查
    board[steps]='?'
    ,然后在该案例中尝试所有四个方向。否则(如果(board[steps]='?')的
    else
    案例)
  • ,只需检查U/D/L/R。由于在大多数步骤中,字符将为“?”,因此您无需在大部分时间进行U/D/L/R测试

  • c=board[steps]
    查找要测试的字符一次,然后在每次测试中使用
    c
    ,而不是
    board[steps]

  • 做这两件事似乎节省了大约5%。我用
    System.currentTimeMillis()做了100次求解和计时
    。我知道有更精确的计时方法,但这已经足够好了,可以看到明显的改进,尽管时间在一次又一次的试验中跳跃了不少。在每种情况下,我所看到的最好结果是最初编写的100次迭代的3600毫秒,而改进后的3400毫秒


    我猜这是最重要的第一个更改。我希望编译器已经在做第二个更改,但我没有单独尝试这两个优化。

    String
    next()
    直接查看IO缓冲区并调用Java内置函数来扫描下一个字符>=
    '
    ,如果有,可能会从中受益。我预计JIT将编译成一个逐字节的循环,但如果有长时间的空白/控制字符运行,SIMD的速度可能会达到16倍。类似地,查找range的非空白字节并将其复制到字符串中;这可以避免StringBuilder,并且(在乐观情况下,在输入缓冲区的结尾之前找到结尾)避免在IO调用过程中保存部分构造的字符串/StringBuilder您是否分析了它的配置文件以找出它在哪里花费了大部分CPU时间?可能是在递归
    solve()中
    ,因此对IO进行微优化可能可以忽略不计。您正在读取的数据的格式是什么?它只是文件中48个字符的字符串吗?如果是,为什么60%的代码只用于从只能包含ASCII字符组合的文件中读取字符串?我将您的FastIO类与FileInputStream cl进行了比较ass,从一个文件中读取随机生成的48个字符的字符串,重复1000次,FileInputStream比你的类快3倍。因此,如果这是计时的一部分,也许你可以用FileInputStream替换你的FastIO类,你就完成了。@Steve IO只是模板的一部分。根据多个sourc是的,这是目前获取Java可用IO的最快方法之一。但是出于某种原因,我刚刚将其切换到BufferedReader,并且我能够在时间限制内提交所有内容。这对于诸如他们有大量输入(大约10^7个不同的整数)之类的问题没有多大意义,这个FastIO能够在大约.3秒内完成,而仅仅使用BufferedReader大约需要.65秒。@Krish:我并不奇怪这些I/O函数适用于大型输入流,因为它们不能全部放在一个缓冲区中(特别是对于整数,但对于字符串字可能没有那么多)。但是您有一个不同的情况,输入很小,可以放在一个输入缓冲区中,对吗?并且可能可以放在任何内部缓冲区标准Java IO类中使用。如果您的大部分CPU时间不是I/O,IDK为什么这会产生很大的差异,但很明显,对于不同的用途,一段代码可以是快的,也可以是慢的-案例。你看到的快速测试案例主要是数字吗?