数组相关算法题

5 篇文章 1 订阅
5 篇文章 0 订阅

一、顺时针打印二维数组

public class PrintArr {
    public static void main(String[] args) {
        int[][] arr = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12},
                {13, 14, 15, 16}
        };
        print(arr);
        Scanner sc = new Scanner(System.in);
        System.out.println();
        System.out.print("请输出一个数(1-20):");
        int N = sc.nextInt();
        int[][] arr1 = new int[N][N];
        print1(arr1);
    }

    /*
    顺时针打印二维数组:
    输入:
    1  2  3  4
    5  6  7  8
    9  10 11 12
    13 14 15 16
    输出:1 2 3 4 8 12 16 15 14 13 9 5 6 7 10 11
     */
    public static void print(int[][] arr) {
        int leftUpRow = 0; // 临时行
        int leftUpCol = 0; // 临时列
        int rightDownRow = arr.length - 1; // 临时最大行
        int rightDownCol = arr[0].length - 1; // 临时最大列
        while (leftUpCol <= rightDownCol || leftUpRow <= rightDownRow) {
            int r = leftUpRow; // 行
            int c = leftUpCol; // 列
            // 右 下 左 上
            while (c <= rightDownCol) {
                System.out.print(arr[r][c++] + " ");
            }
            c--; // 恢复
            r++; // 下一行开始
            while (r <= rightDownRow) {
                System.out.print(arr[r++][c] + " ");
            }
            r--; // 恢复
            c--; // 前一列开始
            while (c >= leftUpCol) {
                System.out.print(arr[r][c--] + " ");
            }
            c++; // 恢复
            r--; // 上一行开始
            while (r > leftUpRow) {
                System.out.print(arr[r--][c] + " ");
            }
            leftUpCol++;
            leftUpRow++;
            rightDownCol--;
            rightDownRow--;
        }
    }
    /*
        从键盘输入一个整数(1~20)
        则以该数字为矩阵的大小,把1,2,3…n*n 的数字按照顺时针螺旋的形式填入其中。
        例如: 输入数字2,则程序输出:
        1 2 
        4 3 
        输入数字3,则程序输出: 
        1 2 3 
        8 9 4 
        7 6 5 
        输入数字4, 则程序输出: 
        1   2   3   4 
        12  13  14   5 
        11  16  15   6 
        10  9   8   7
    */
    public static void print1(int[][] arr) {
        int leftUpRow = 0; // 临时行
        int leftUpCol = 0; // 临时列
        int rightDownRow = arr.length - 1; // 临时最大行
        int rightDownCol = arr[0].length - 1; // 临时最大列
        int x=1;
        while (leftUpCol <= rightDownCol || leftUpRow <= rightDownRow) {
            int r = leftUpRow; // 行
            int c = leftUpCol; // 列
            // 右 下 左 上
            while (c <= rightDownCol) {
                arr[r][c++]=x++;
            }
            c--; // 恢复
            r++; // 下一行开始
            while (r <= rightDownRow) {
                arr[r++][c]=x++;
            }
            r--; // 恢复
            c--; // 前一列开始
            while (c >= leftUpCol) {
                arr[r][c--]=x++;
            }
            c++; // 恢复
            r--; // 上一行开始
            while (r > leftUpRow) {
                arr[r--][c]=x++;
            }
            leftUpCol++;
            leftUpRow++;
            rightDownCol--;
            rightDownRow--;
        }
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j]+"\t");
            }
            System.out.println();
        }
    }
}

二、将0所在行列清0

public class Clear_0 {
    public static void main(String[] args) {
        int[][] arr = {
                {1, 2, 3, 4},
                {5, 0, 0, 8},
                {9, 10, 11, 12}
        };
        clear(arr);
    }

    public static void clear(int[][] arr) {
        int[] rowRecord = new int[arr.length]; // 记录行
        int[] colRecord = new int[arr[0].length]; // 记录列
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                if (arr[i][j] == 0) {
                    rowRecord[i] = 1;
                    colRecord[j] = 1;
                }
            }
        }
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[0].length; j++) {
                if (rowRecord[i] == 1 || colRecord[j] == 1) {
                    arr[i][j] = 0; // 把行或列为0的元素记为0
                }
            }
        }
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}

三、Z形打印二维数组

数组:
1 2 3 4
5 6 7 8
9 10 11 12
打印:
1 2 5 9 6 3 4 7 10 11 8 12

public class Print_Z {
    public static void main(String[] args) {
        int[][] arr = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12}
        };
        print(arr);
    }

    public static void print(int[][] arr) {
        int r = 0, m = arr.length; // 控制行
        int c = 0, n = arr[0].length; // 控制列
        boolean flag = true;
        while (r < m && c < n) {
            if (flag) { // 左下往右上的斜线
                System.out.print(arr[r][c] + " ");
                if (r == 0 && c < n - 1) { // 第一行非最后一列
                    flag = !flag;
                    c++; // 到下一列开始
                    continue;
                } else if (r > 0 && c == n - 1) { // 最后一列非第一行
                    flag = !flag;
                    r++;
                    continue;
                } else {
                    r--;
                    c++;
                }
            } else { // 从右上往斜下的斜线
                System.out.print(arr[r][c] + " ");
                if (c == 0 && r < m - 1) { // 第一列非最后一行
                    flag = !flag;
                    r++;
                    continue;
                } else if (c > 0 && r == m - 1) { // 最后一行非第一列
                    flag = !flag;
                    c++;
                    continue;
                } else {
                    r++;
                    c--;
                }
            }
        }
    }
}

四、最大子方阵

给定一个N * N的矩阵matrix,在这个矩阵中,只有0和1两种值,
返回边框全是1的最大正方形的边长长度
例如:
{0,1,1,1,1},
{0,1,0,0,1},
{0,1,0,0,1},
{0,1,1,1,1},
{0,1,0,1,1}
其中,边框全是1的最大正方形的大小是4 * 4,返回4

public class MaxArr {
    public static void main(String[] args) {
        int[][] arr = {
                {0, 1, 1, 1, 1},
                {0, 1, 0, 0, 1},
                {0, 1, 0, 0, 1},
                {0, 1, 1, 1, 1},
                {0, 1, 0, 1, 1}
        };
        int max = max(arr);
        System.out.println(max);
    }

    public static int max(int[][] arr) {
        int N = arr.length;
        int n = N; // 当前最大的边长
        int r, c;
        while (n > 0) {
            for (int i = 0; i < N; i++) {
                if (i + n > N) { // 越界 不满足条件 n减少
                    break;
                }
                l3:
                for (int j = 0; j < N; j++) {
                    if (j + n > N) { // 越界 不满足条件 下一行
                        break;
                    }
                    // i,j就是顶点,当前起点
                    r = i;
                    c = j;
                    // 右
                    while (c < j + n) { // 小于最后一列,往右走
                        if (arr[r][c++] == 0) { // 等于0则跳过
                            continue l3;
                        }
                    }
                    c--; // 恢复
                    // 下
                    while (r < i + n) { // 小于最后一行,往下走
                        if (arr[r++][c] == 0) { // 等于0则跳过
                            continue l3;
                        }
                    }
                    r--; // 恢复
                    // 左
                    while (c >= j) { // 大于要比较元素的那一列,往左走
                        if (arr[r][c--] == 0) {
                            continue l3;
                        }
                    }
                    c++; // 恢复
                    // 上
                    while (r >= i) {
                        if (arr[r--][c] == 0) {
                            continue l3;
                        }
                    }
                    return n;
                }
            }
            n--;
        }
        return 0;
    }
}

五、最大子方阵优化

public class MaxArrPlus {

    static int[][][] rec; // 记录每个顶点的右边和下边1的个数

    public static void main(String[] args) {
        int[][] arr = {
                {0, 1, 1, 1, 1},
                {0, 1, 0, 0, 1},
                {0, 1, 0, 0, 1},
                {0, 1, 1, 1, 1},
                {0, 1, 0, 1, 1}
        };
        help(arr); // 辅助矩阵
        for (int i = 0; i < rec.length; i++) { // 输出辅助矩阵
            for (int j = 0; j < rec[i].length; j++) {
                System.out.print("(" + rec[i][j][0] + "," + rec[i][j][1] + ")\t");
            }
            System.out.println();
        }
        System.out.println(max(arr));
    }

    public static int max(int[][] arr) {
        int N = arr.length;
        int n = N;
        while (n > 0) {
            for (int i = 0; i < N; i++) {
                if (i + n > N) {
                    break;
                }
                for (int j = 0; j < N; j++) {
                    if (j + n > N) {
                        break;
                    }
                    if (check(i, j, n)) {
                        return n;
                    }
                }
            }
            n--;
        }
        return 0;
    }

    private static boolean check(int i, int j, int n) {
        // rec[i][j][0]>=n:当前元素的右边有大于n个1
        // rec[i][j][1]>=n:当前元素的下边有大于n个1
        // rec[i][j+n-1][1]>=n:当前元素右边第n个元素的下边有大于n个1
        // rec[i+n-1][j][0]>=n:当前元素下边第n个元素的右边有大于n个1
        if (rec[i][j][0] >= n && rec[i][j][1] >= n &&
                rec[i][j + n - 1][1] >= n && rec[i + n - 1][j][0] >= n) {
            return true;
        }
        return false;
    }

    // 预处理 记录右边和下边1的个数
    private static void help(int[][] arr) {
        int N = arr.length;
        rec = new int[N][N][2]; // rec[0][0][0]:顶点00右边1的个数 rec[0][0][1]:顶点00下边1的个数
        int row = N - 1; // 最后一行索引
        // 处理最后一行
        for (int j = N - 1; j >= 0; j--) { // 倒序遍历
            int value = arr[row][j]; // 当前值
            if (value == 1) {
                rec[row][j][1] = 1; // 最后一行下边没有数字 自身为1个
                if (j == N - 1) { // 最后一列 右边没有数字 自身为1个
                    rec[row][j][0] = 1; // 右边连续1的个数
                } else {
                    rec[row][j][0] = rec[row][j + 1][0] + 1; // 右边连续1的个数+本身
                }
            }
        }
        row--; // 从倒数第二行开始从右到左 从下到上遍历
        for (int i = row; i >= 0; i--) {
            for (int j = N - 1; j >= 0; j--) {
                int value = arr[i][j]; // 当前遍历的值
                if (value == 1) {
                    if (j == N - 1) { // 最后一列
                        rec[i][j][0] = 1; // 右边只有本身
                        rec[i][j][1] = rec[i + 1][j][1] + 1; // 下边+本身
                    } else {
                        rec[i][j][0] = rec[i][j + 1][0] + 1; // 右边连续1的个数
                        rec[i][j][1] = rec[i + 1][j][1] + 1; // 下边连续1的个数
                    }
                }
            }
        }
    }
}

六、子数组的最大累加和

给定一个数组arr,返回子数组的最大累加和
例:arr=[1,-2,3,5,-2,6,-1];所有的子数组中[3,5,-2,6]可以累加出最大的和12,所以返回12

public class MaxSum {
    public static void main(String[] args) {
        int[] arr = {1, -2, 3, 5, -2, 6, -1};
        findByForce(arr);
        findByDp(arr);
    }

    // 暴力解法
    public static void findByForce(int[] arr) {
        int maxSum = arr[0];
        for (int i = 0; i < arr.length; i++) {
            int sum = arr[i];
            int maxOfJ = sum;
            for (int j = i + 1; j < arr.length; j++) {
                sum += arr[j];
                if (sum > maxOfJ) {
                    maxOfJ = sum;
                }
            }
            if (maxOfJ > maxSum) {
                maxSum = maxOfJ;
            }
        }
        System.out.println(maxSum);
    }

    // 部分整体负数丢弃,正数保留
    static void findByDp(int[] arr) {
        int sumJ = arr[0]; // 前j个元素的最大贡献
        int max = sumJ;
        int left = 0; // 记录子数组左边
        int right = 0; // 记录子数组右边
        for (int i = 1; i < arr.length; i++) {
            if (sumJ >= 0) { // 留着累加
                sumJ += arr[i];
            } else { // 去掉前面的重新累加
                sumJ = arr[i];
                left = i; // 开始位置
            }
            if (sumJ > max) { // 更新最大值
                max = sumJ;
                right = i; // 结束位置
            }
        }
        System.out.println(max + ",left=" + left + ",right=" + right);
    }
}

七、子矩阵的最大累加和

子数组的最大累加和的扩展,把每一列看成是一个值,降维处理

给定一个矩阵matrix,其中的值有正、有负、有0,返回子矩阵的最大累加和
例如:matrix为:
-1 -1 -1
-1 2 2
-1 -1 -1
其中最大累加和的子矩阵为:
2 2
所以返回4

import java.util.Arrays;

public class MaxArrSum {
    public static void main(String[] args) {
        int[][] arr = {
                {-1, -1, -1},
                {-1, 2, 2},
                {-1, -1, -1}
        };
        System.out.println(maxSum(arr));
    }

    static int maxSum(int[][] matrix) {
        if (matrix.length == 0) {
            return 0;
        }
        int beginRow = 0; // 起始行
        final int M = matrix.length; // 行数
        final int N = matrix[0].length; // 列数
        int[] sums = new int[N]; // 记录每一列的和
        int max = 0; // 历史最大的子矩阵和
        while (beginRow < M) {
            for (int i = beginRow; i < M; i++) {
                // 按列累加
                for (int j = 0; j < N; j++) {
                    sums[j] += matrix[i][j];
                }
                // 累加完成
                int t = findByDp(sums);
                if (t > max) {
                    max = t;
                }
            }
            Arrays.fill(sums, 0); // 初始化sums
            beginRow++;
        }
        return max;
    }

    static int findByDp(int[] arr) {
        int sumJ = arr[0]; // 前j个元素的最大贡献
        int max = sumJ;
        for (int i = 1; i < arr.length; i++) {
            if (sumJ >= 0) { // 留着累加
                sumJ += arr[i];
            } else { // 去掉前面的重新累加
                sumJ = arr[i];
            }
            if (sumJ > max) { // 更新最大值
                max = sumJ;
            }
        }
        return max;
    }
}

八、排序数组中找和的因子

给定已排序数组arr和k,不重复打印arr中所有相加和为k的不降序二元组
如:输入arr={-8,-4,-3,0,2,4,5,8,9,10},k=10
输出:(0,10)(2,8)

public class SortArrSum {
    public static void main(String[] args) {
        int[] arr = {-8, -4, -3, 0, 2, 4, 5, 8, 9, 10};
        sum(arr, 10);
        sum1(arr, 10);
    }

    // 暴力
    public static void sum(int[] arr, int k) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[i] + arr[j] == k) {
                    System.out.print("(" + arr[i] + "," + arr[j] + ") ");
                }
            }
        }
    }

    // 指针移动
    public static void sum1(int[] arr, int k) {
        int left = 0; // 左
        int right = arr.length - 1; // 右
        while (left < right) {
            if (arr[left] + arr[right] == k) { // 相等则输出
                System.out.print("(" + arr[left] + "," + arr[right] + ") ");
                left++; // 继续判断下一个数
            }else if (arr[left]+arr[right]>k){ // 大于则right前移加小的
                right--;
            }else { // 小于则往后走
                left++;
            }
        }
    }
}

九、需要排序的子数组

给定一个无序数组arr,求出需要排序的最短子数组长度
要求时间复杂度O(n)
如输入:arr={2,3,7,5,4,6}
返回4,因为只有{7,5,4,6}需要排序

public class NeedSortArr {
    public static void main(String[] args) {
        int[] arr = {2, 3, 4, 5, 4, 6};
        needSortArr(arr);
    }

    public static void needSortArr(int[] arr) {
        int n = arr.length;
        int max = arr[0]; // 左边最大的元素
        int min = arr[n - 1]; // 右边最小的元素
        int invalidRight = 0; // 记录不符合条件最右边的索引
        int invalidLeft = -1; // 记录不符合条件的最左边的索引
        // 1.从左向右遍历,找出不合适数的最右范围:从左往右遍历,如果 maxLeft > 当前元素,
        // 则记录它的位置到 invalidRight ,一直遍历到最右边
        for (int i = 1; i < n; i++) {
            if (max <= arr[i]) {
                max = arr[i];
            } else {
                invalidRight = i;
            }
        }
        // 2.从右向左遍历,找出不合适数的最左范围:从右往左遍历,如果当前元素 > minRight,
        // 则记录它的位置为 invalidLeft,一直遍历到最左边
        for (int i = n - 2; i >= 0; i--) {
            if (min >= arr[i]) {
                min = arr[i];
            } else {
                invalidLeft = i;
            }
        }
        // 如果invalidLeft没有改变过,则说明数组有序
        if (invalidLeft == -1) {
            System.out.println(0);
            return;
        }
        // 3.invalidRight - invalidLeft + 1 就是需要排序的最短子数组长度
        System.out.println(invalidRight - invalidLeft + 1);
        for (int i = invalidLeft; i <= invalidRight; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

十、矩阵运算

A+2X=B,求未知矩阵X

import java.util.Scanner;

public class Matrix {
    public static void main(String[] args) {
        // 初始化 输入
        Scanner sc = new Scanner(System.in);
        System.out.print("行=");
        int M = sc.nextInt();//M行
        System.out.print("列=");
        int N = sc.nextInt();//N列
        int[][] A = new int[M][N];
        int[][] B = new int[M][N];
        System.out.println("A:");
        for (int i = 0; i < A.length; i++) {
            for (int j = 0; j < A[i].length; j++) {
                A[i][j] = sc.nextInt();
            }
        }
        System.out.println("B:");
        for (int i = 0; i < B.length; i++) {
            for (int j = 0; j < B[i].length; j++) {
                B[i][j] = sc.nextInt();
            }
        }
        
        // A+2X=B => X=(B-A)/2
        System.out.println("X:");
        double[][] X = getX(A, B); // 求X
        // 输出结果
        for (int i = 0; i < X.length; i++) {
            for (int j = 0; j < X[i].length; j++) {
                System.out.print(X[i][j] + " ");
            }
            System.out.println();
        }
        
        // 拓展A*B
        int[][] mul = mul(A, B); // A*B
        // 输出结果
        for (int[] S : mul) {
            for (int x : S) {
                System.out.print(x + "\t");
            }
            System.out.println();
        }
    }

    // A*B 结果为A行B列 A的行数要和B的列数相等
    public static int[][] mul(int[][] A, int[][] B) {
        int[][] X = new int[A.length][B[0].length];
        int row = 0; // 控制行
        int col = 0; // 控制列
        while (row < A.length) { // 小于A的行数
            // 一行一行计算
            while (col < B[0].length) { // 小于B的列数
                for (int j = 0; j < A.length; j++) {
                    X[row][col] += (A[row][j] * B[j][col]);
                }
                col++; // 计算第row行,下一列
            }
            row++; // 下一行
            col = 0;
        }
        return X;
    }

    public static double[][] getX(int[][] A, int[][] B) {
        double[][] X = new double[A.length][A[0].length];
        for (int i = 0; i < A.length; i++) {
            for (int j = 0; j < A[i].length; j++) {
                double a = B[i][j] - A[i][j];
                X[i][j] = a / 2;
            }
        }
        return X;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明仔爱编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值