继续继续~~

package class03;

import org.junit.Test;

public class study230724 {
    //1.滑动窗口的例题:
    // 给定一个有序数组arr,从左到右依次表示一个点,现在有一个长度len的绳子,求绳子最大覆盖的点数
    public int qes1(int[] arr, int len) {
        //思路1:将绳子的右端固定在每个点上,找到arr[i]-L的第一个点index,一直滑动
        int res = 0;
        for (int R = 0; R < arr.length; R++) {
            int m = arr[R] - len;
            int j = 0;
            while (arr[j] < m) {
                j++;
            }
            res = Math.max(res, R - j + 1);
        }
        return res;
    }

    //打表法
    //对于一个整数n,满足n=i*6+8*j (i,j)均为整数,返回i+j的最小值,不满足返回-1
    public int qes2(int n) {
        //分析n=i*6+8*j => n = 2(3*i+4*j) => n是偶数,才能存在这样的i,j
        if ((n & 1) != 0) {
            return -1;
        }
        int m = n / 8;
        while (m >= 0) {
            int i = n - 8 * m;
            if (i > 25) {
                return -1;
            }
            if (i % 6 == 0) {
                return m + i / 6;
            }
            m--;
        }
        return m;
    }

    //方法2:整数输入和整数输出 可以考虑打表法,分析发现从3开始,每轮都有4个数带上-1,8个为一轮
    //-1 -1 -1 -1 -1 1
    //-1 1 -1 -1 -1 2
    //-1 2 -1 2 -1

    // 3 -1 3 -1 3 -1 3 -1
    // 4 -1 4 -1 4 -1 4 -1  26
    // 5 -1 5 -1 5 -1 5 -1  34
    // 6 -1 6 -1 6 -1 6 -1
    // 7 -1 7 -1 7 -1 7 -1
    // 8 -1 8
    //-1 8 -1 8 -1 9
    //-1 9 -1 9 -1 9
    //-1 10 -1 10 -1 10
    //-1 10 -1 11 -1 11
    //-1 11 -1 11 -1 12
    //-1 12 -1 12 -1 12
    //-1 13 -1 13
    //Process finished with exit code 0
    public int qes3(int n) {
        if ((n & 1) != 0) {
            return -1;
        }
        if (n >= 18) {
            return (n - 18) / 8 + 3;
        } else {
            if (n == 6 || n == 8) {
                return 1;
            } else if (n == 12 || n == 14 || n == 16) {
                return 2;
            }
        }
        return -1;
    }

    //打表法2:对于一个数n,有两个人A,B先后拿走4的i次方的数字,拿走最后一个数的人会赢,
    //对于n,问先后谁赢?
    //小贪心算法,如果A拿走 m = 4的i(0~log n)可以赢,那就拿走m; 不能赢,再去考虑拿走i++次方的数
    //经发现实际上就是A B A A B循环,直接打表计算即可
    public String qes5(int n) {
        if (n == 0) {
            return "B";
        }
        if (n == 1) {
            return "A";
        }
        int i = 1;
        while (i <= n) {
            if (qes5(n - i).equals("B")) {  //子过程中表示后手 实际上是母过程的先手
                return "A";
            }
            if (i > n / 4) {
                break;
            }
            i = i * 4;
        }
        return "B";
    }

    //预处理技巧
    //问题6:一排正方形进行染红色和绿色,原始正方形已经已存在颜色,比如RGGRRGG
    //染色要求是:绿色G的左边不能有红色R,求最少的染色次数能够达到要求
    public int qes6(String str) {
        int res = str.length();
        //思路:G的左边不能存在R表示G的左边只能有G=>GGGGRRRR结构
        //定义左右的分界线i(0~n-1) [0~i)是左边G,[i~n-1]是右边R
        //判断左边有多少R个数,右边有多少G的个数,之和就是i变更的染色次数,
        //判断i的最小
        for (int i = 0; i < str.length(); i++) {
            int Rcount = 0;
            for (int j = 0; j < i; j++) {
                if (str.charAt(j) == 'R')
                    Rcount++;
            }
            int Gcount = 0;
            for (int j = i; j < str.length(); j++) {
                if (str.charAt(j) == 'G')
                    Gcount++;
            }
            res = Math.min(Rcount + Gcount, res);
        }
        return res;
    }

    //对于问题6 ,子循环可以采用预处理技巧,利用空间换时间,增加两个数组A B
    //A从左到右统计R的数量,B从右到左统计G的数量,从而减少时间复杂度
    public int qes6_1(String str) {
        int len = str.length();
        int res = len;
        int[] Rcount = new int[len];
        Rcount[0] = str.charAt(0) == 'R' ? 1 : 0;
        for (int i = 1; i < len; i++) {
            Rcount[i] = str.charAt(i) == 'R' ? Rcount[i - 1] + 1 : Rcount[i - 1];
        }
        int[] Gcount = new int[len];
        Gcount[len - 1] = str.charAt(len - 1) == 'G' ? 1 : 0;
        for (int i = len - 2; i >= 0; i--) {
            Gcount[i] = str.charAt(i) == 'G' ? Gcount[i + 1] + 1 : Gcount[i + 1];
        }  //预处理i的左右两端RG的数量,减少时间复杂度

        for (int i = 0; i < len; i++) {
            res = Math.min(Rcount[i] + Gcount[i] - 1, res); //
        }
        return res;
    }

    //预处理7,对于一个N*N的(0,1)组成的矩阵arr,求矩阵内边数全是1的最大正方形边长
    //根据给定的代码,可能存在以下问题:
    //1. 循环边界条件错误:在第一个for循环中,循环条件为 i < N ,应该改为 i < N-1 ,因为在内部循环中,会访问到 arr[i + k-1] ,如果 i 等于 N ,则会超出数组边界。
    //2. 正方形边长计算错误:在第三个for循环中,循环条件为 l < j + k ,应该改为 l < j + k + 1 ,因为正方形的边长应该是 k+1 。
    //3. 逻辑错误:在判断正方形的四个边是否都是1时,应该使用或运算符 || 而不是与运算符 && ,因为只要有一个边不是1,就应该跳出循环。
    public int qes7(int[][] arr) {
        //分析:在一个N*N的矩阵内,可以组成正方形有n的三次方可能
        int res = 1;
        //int M = arr.length;
        int N = arr[0].length;
        for (int i = 1; i < N; i++) {
            for (int j = 1; j < N; j++) {  //(i,j正方形左上角点坐标集合)
                for (int k = 1; k < Math.min(N - i, N - j); k++) {  //正方形边长
                    boolean flag = false;
                    //依次判断正方形的四个边是否都是1
                    for (int l = j; l < j + k; l++) {
                        if (arr[i - 1][l] != 1) {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag) {
                        for (int l = j; l < j + k; l++) {
                            if (arr[i + k - 1][l] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        for (int l = i; l < i + k; l++) {
                            if (arr[l][j] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        for (int l = i; l < i + k; l++) {
                            if (arr[l][j + k] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        res = Math.max(res, k);
                    }
                }
            }
        }
        return res;
    }

    //修复后代码
    public int qes7_2(int[][] arr) {
        int res = 1;
        int N = arr[0].length;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                for (int k = 1; k < Math.min(N - i, N - j); k++) {
                    boolean flag = false;
                    for (int l = j; l < j + k + 1; l++) {
                        if (arr[i][l] != 1 || arr[i + k][l] != 1) {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag) {
                        for (int l = i; l < i + k + 1; l++) {
                            if (arr[l][j] != 1 || arr[l][j + k] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        res = Math.max(res, k + 1);
                    }
                }
            }
        }
        return res;
    }

    //在ques7_2中,出现大量的重复代码,并且在O(n4),那我们要考虑到减少时间复杂度,
    //定义right[i][j]表示(i,j)坐标右边包含自己有多少个连续的1
    //定义down[i][j]表示(i,j)坐标下边包含自己有多少个连续的1

    public int qes7_3(int[][] arr) {
        int res = 1;
        int N = arr[0].length;
        int[][] right = new int[N][N];
        int[][] down = new int[N][N];

        for (int i = 0; i < N; i++) {
            right[i][N - 1] = arr[i][N - 1]; //处理边界
            for (int j = N - 2; j >= 0; j--) {
                right[i][j] = arr[i][j] == 0 ? 0 : right[i][j + 1] + 1;
            }
        }

        for (int i = 0; i < N; i++) {
            down[N - 1][i] = arr[N - 1][i]; //处理边界
            for (int j = N - 2; j >= 0; j--) {
                down[j][i] = arr[j][i] == 0 ? 0 : down[j + 1][i] + 1;
            }
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                for (int k = 1; k < Math.min(N - i, N - j); k++) {
                    if (right[i][j] > k && down[i][j] > k && down[i][j + k] > k && right[i + k][j] > k) {
                        res = Math.max(res, k + 1);
                    }
                }
            }
        }

        return res;
    }

    @Test
    public void Test() {

        int[] ints = {1, 2, 4, 7, 9, 11, 15};
        int i = qes1(ints, 6);
        System.out.println("最大覆盖点数是" + i);

//        System.out.println("打表法:");
//        for (int j = 1; j <= 100; j++) {
//            System.out.print(qes2(j) + " ");
//            if (j % 6 == 0) {
//                System.out.println();
//            }
//        }
//        System.out.println();
//        for (int j = 1; j < 101; j++) {
//            System.out.print(qes5(j) + " ");
//            if (j % 5 == 0) {
//                System.out.println();
//            }
//        }
        System.out.println();
        System.out.println("最少染色次数");
        long l1 = System.nanoTime();
        String s = "GGGGGRGRGRGRGGRGRGGGGGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGRGGRGRGRRRRGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGRRRRGRGRGR";
        int i1 = qes6(s);
        System.out.println(i1);
        long l2 = System.nanoTime();
        System.out.println((l2 - l1) / 1000000 + "时间");

        l1 = System.nanoTime();
        int i2 = qes6_1(s);
        System.out.println(i2);
        l2 = System.nanoTime();
        System.out.println((l2 - l1) / 1000000 + "时间");

        //
        System.out.println("边长最大");
        int[][] ints1 = {

                {0, 1, 1, 1, 1},
                {0, 1, 0, 1, 1},
                {0, 1, 1, 1, 1},
                {0, 1, 1, 1, 1},
                {0, 0, 0, 0, 0}
        };
        int i3 = qes7_2(ints1);
        int i4 = qes7_3(ints1);
        System.out.println(i3 + "==?" + i4);

    }
}

package class03;

import org.junit.Test;

public class study230724 {
    //1.滑动窗口的例题:
    // 给定一个有序数组arr,从左到右依次表示一个点,现在有一个长度len的绳子,求绳子最大覆盖的点数
    public int qes1(int[] arr, int len) {
        //思路1:将绳子的右端固定在每个点上,找到arr[i]-L的第一个点index,一直滑动
        int res = 0;
        for (int R = 0; R < arr.length; R++) {
            int m = arr[R] - len;
            int j = 0;
            while (arr[j] < m) {
                j++;
            }
            res = Math.max(res, R - j + 1);
        }
        return res;
    }

    //打表法
    //对于一个整数n,满足n=i*6+8*j (i,j)均为整数,返回i+j的最小值,不满足返回-1
    public int qes2(int n) {
        //分析n=i*6+8*j => n = 2(3*i+4*j) => n是偶数,才能存在这样的i,j
        if ((n & 1) != 0) {
            return -1;
        }
        int m = n / 8;
        while (m >= 0) {
            int i = n - 8 * m;
            if (i > 25) {
                return -1;
            }
            if (i % 6 == 0) {
                return m + i / 6;
            }
            m--;
        }
        return m;
    }

    //方法2:整数输入和整数输出 可以考虑打表法,分析发现从3开始,每轮都有4个数带上-1,8个为一轮
    //-1 -1 -1 -1 -1 1
    //-1 1 -1 -1 -1 2
    //-1 2 -1 2 -1

    // 3 -1 3 -1 3 -1 3 -1
    // 4 -1 4 -1 4 -1 4 -1  26
    // 5 -1 5 -1 5 -1 5 -1  34
    // 6 -1 6 -1 6 -1 6 -1
    // 7 -1 7 -1 7 -1 7 -1
    // 8 -1 8
    //-1 8 -1 8 -1 9
    //-1 9 -1 9 -1 9
    //-1 10 -1 10 -1 10
    //-1 10 -1 11 -1 11
    //-1 11 -1 11 -1 12
    //-1 12 -1 12 -1 12
    //-1 13 -1 13
    //Process finished with exit code 0
    public int qes3(int n) {
        if ((n & 1) != 0) {
            return -1;
        }
        if (n >= 18) {
            return (n - 18) / 8 + 3;
        } else {
            if (n == 6 || n == 8) {
                return 1;
            } else if (n == 12 || n == 14 || n == 16) {
                return 2;
            }
        }
        return -1;
    }

    //打表法2:对于一个数n,有两个人A,B先后拿走4的i次方的数字,拿走最后一个数的人会赢,
    //对于n,问先后谁赢?
    //小贪心算法,如果A拿走 m = 4的i(0~log n)可以赢,那就拿走m; 不能赢,再去考虑拿走i++次方的数
    //经发现实际上就是A B A A B循环,直接打表计算即可
    public String qes5(int n) {
        if (n == 0) {
            return "B";
        }
        if (n == 1) {
            return "A";
        }
        int i = 1;
        while (i <= n) {
            if (qes5(n - i).equals("B")) {  //子过程中表示后手 实际上是母过程的先手
                return "A";
            }
            if (i > n / 4) {
                break;
            }
            i = i * 4;
        }
        return "B";
    }

    //预处理技巧
    //问题6:一排正方形进行染红色和绿色,原始正方形已经已存在颜色,比如RGGRRGG
    //染色要求是:绿色G的左边不能有红色R,求最少的染色次数能够达到要求
    public int qes6(String str) {
        int res = str.length();
        //思路:G的左边不能存在R表示G的左边只能有G=>GGGGRRRR结构
        //定义左右的分界线i(0~n-1) [0~i)是左边G,[i~n-1]是右边R
        //判断左边有多少R个数,右边有多少G的个数,之和就是i变更的染色次数,
        //判断i的最小
        for (int i = 0; i < str.length(); i++) {
            int Rcount = 0;
            for (int j = 0; j < i; j++) {
                if (str.charAt(j) == 'R')
                    Rcount++;
            }
            int Gcount = 0;
            for (int j = i; j < str.length(); j++) {
                if (str.charAt(j) == 'G')
                    Gcount++;
            }
            res = Math.min(Rcount + Gcount, res);
        }
        return res;
    }

    //对于问题6 ,子循环可以采用预处理技巧,利用空间换时间,增加两个数组A B
    //A从左到右统计R的数量,B从右到左统计G的数量,从而减少时间复杂度
    public int qes6_1(String str) {
        int len = str.length();
        int res = len;
        int[] Rcount = new int[len];
        Rcount[0] = str.charAt(0) == 'R' ? 1 : 0;
        for (int i = 1; i < len; i++) {
            Rcount[i] = str.charAt(i) == 'R' ? Rcount[i - 1] + 1 : Rcount[i - 1];
        }
        int[] Gcount = new int[len];
        Gcount[len - 1] = str.charAt(len - 1) == 'G' ? 1 : 0;
        for (int i = len - 2; i >= 0; i--) {
            Gcount[i] = str.charAt(i) == 'G' ? Gcount[i + 1] + 1 : Gcount[i + 1];
        }  //预处理i的左右两端RG的数量,减少时间复杂度

        for (int i = 0; i < len; i++) {
            res = Math.min(Rcount[i] + Gcount[i] - 1, res); //
        }
        return res;
    }

    //预处理7,对于一个N*N的(0,1)组成的矩阵arr,求矩阵内边数全是1的最大正方形边长
    //根据给定的代码,可能存在以下问题:
    //1. 循环边界条件错误:在第一个for循环中,循环条件为 i < N ,应该改为 i < N-1 ,因为在内部循环中,会访问到 arr[i + k-1] ,如果 i 等于 N ,则会超出数组边界。
    //2. 正方形边长计算错误:在第三个for循环中,循环条件为 l < j + k ,应该改为 l < j + k + 1 ,因为正方形的边长应该是 k+1 。
    //3. 逻辑错误:在判断正方形的四个边是否都是1时,应该使用或运算符 || 而不是与运算符 && ,因为只要有一个边不是1,就应该跳出循环。
    public int qes7(int[][] arr) {
        //分析:在一个N*N的矩阵内,可以组成正方形有n的三次方可能
        int res = 1;
        //int M = arr.length;
        int N = arr[0].length;
        for (int i = 1; i < N; i++) {
            for (int j = 1; j < N; j++) {  //(i,j正方形左上角点坐标集合)
                for (int k = 1; k < Math.min(N - i, N - j); k++) {  //正方形边长
                    boolean flag = false;
                    //依次判断正方形的四个边是否都是1
                    for (int l = j; l < j + k; l++) {
                        if (arr[i - 1][l] != 1) {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag) {
                        for (int l = j; l < j + k; l++) {
                            if (arr[i + k - 1][l] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        for (int l = i; l < i + k; l++) {
                            if (arr[l][j] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        for (int l = i; l < i + k; l++) {
                            if (arr[l][j + k] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        res = Math.max(res, k);
                    }
                }
            }
        }
        return res;
    }

    //修复后代码
    public int qes7_2(int[][] arr) {
        int res = 1;
        int N = arr[0].length;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                for (int k = 1; k < Math.min(N - i, N - j); k++) {
                    boolean flag = false;
                    for (int l = j; l < j + k + 1; l++) {
                        if (arr[i][l] != 1 || arr[i + k][l] != 1) {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag) {
                        for (int l = i; l < i + k + 1; l++) {
                            if (arr[l][j] != 1 || arr[l][j + k] != 1) {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        res = Math.max(res, k + 1);
                    }
                }
            }
        }
        return res;
    }

    //在ques7_2中,出现大量的重复代码,并且在O(n4),那我们要考虑到减少时间复杂度,
    //定义right[i][j]表示(i,j)坐标右边包含自己有多少个连续的1
    //定义down[i][j]表示(i,j)坐标下边包含自己有多少个连续的1

    public int qes7_3(int[][] arr) {
        int res = 1;
        int N = arr[0].length;
        int[][] right = new int[N][N];
        int[][] down = new int[N][N];

        for (int i = 0; i < N; i++) {
            right[i][N - 1] = arr[i][N - 1]; //处理边界
            for (int j = N - 2; j >= 0; j--) {
                right[i][j] = arr[i][j] == 0 ? 0 : right[i][j + 1] + 1;
            }
        }

        for (int i = 0; i < N; i++) {
            down[N - 1][i] = arr[N - 1][i]; //处理边界
            for (int j = N - 2; j >= 0; j--) {
                down[j][i] = arr[j][i] == 0 ? 0 : down[j + 1][i] + 1;
            }
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                for (int k = 1; k < Math.min(N - i, N - j); k++) {
                    if (right[i][j] > k && down[i][j] > k && down[i][j + k] > k && right[i + k][j] > k) {
                        res = Math.max(res, k + 1);
                    }
                }
            }
        }

        return res;
    }

    @Test
    public void Test() {

        int[] ints = {1, 2, 4, 7, 9, 11, 15};
        int i = qes1(ints, 6);
        System.out.println("最大覆盖点数是" + i);

//        System.out.println("打表法:");
//        for (int j = 1; j <= 100; j++) {
//            System.out.print(qes2(j) + " ");
//            if (j % 6 == 0) {
//                System.out.println();
//            }
//        }
//        System.out.println();
//        for (int j = 1; j < 101; j++) {
//            System.out.print(qes5(j) + " ");
//            if (j % 5 == 0) {
//                System.out.println();
//            }
//        }
        System.out.println();
        System.out.println("最少染色次数");
        long l1 = System.nanoTime();
        String s = "GGGGGRGRGRGRGGRGRGGGGGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGRGGRGRGRRRRGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGGGGGRGRGRGRGGRGRGRRRRGRGRGRGRRRRGRGRGR";
        int i1 = qes6(s);
        System.out.println(i1);
        long l2 = System.nanoTime();
        System.out.println((l2 - l1) / 1000000 + "时间");

        l1 = System.nanoTime();
        int i2 = qes6_1(s);
        System.out.println(i2);
        l2 = System.nanoTime();
        System.out.println((l2 - l1) / 1000000 + "时间");

        //
        System.out.println("边长最大");
        int[][] ints1 = {

                {0, 1, 1, 1, 1},
                {0, 1, 0, 1, 1},
                {0, 1, 1, 1, 1},
                {0, 1, 1, 1, 1},
                {0, 0, 0, 0, 0}
        };
        int i3 = qes7_2(ints1);
        int i4 = qes7_3(ints1);
        System.out.println(i3 + "==?" + i4);

    }
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值