一、顺时针打印二维数组
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;
}
}