System.out.println(i);
//结果输出为:5而不是4!!!
这点很重要,可以看看剑指offer中的顺时针打印矩阵这道题,我刚开始做出现Exception:数组越界问题,问题来源就是这个。参考代码:
import java.util.ArrayList;
public class Solution {
public ArrayList printMatrix(int [][] matrix) {
ArrayList list=new ArrayList();
fun(matrix,list);
return list;
}
public void fun(int [][] matrix,ArrayList list){
if(matrix==null){
return;
}
int xlen=matrix.length;
int ylen=matrix[0].length;
if(matrix.length==1){
for(int i=0;i<matrix[0].length;i++){
list.add(matrix[0][i]);
}
return;
}
if(matrix[0].length==1){
for(int i=0;i<matrix.length;i++){
list.add(matrix[i][0]);
}
return;
}
int i=0,j;
for(j=0;j<matrix[i].length;j++){
list.add(matrix[i][j]);
}
j=j-1;
for(i=1;i<matrix.length;i++){
list.add(matrix[i][j]);
}
i=i-1;
for(j=j-1;j>=0;j–){
list.add(matrix[i][j]);
}
j=j+1;
for(i=i-1;i>0;i–){
list.add(matrix[i][j]);
}
if(xlen-2<=0||ylen-2<=0){
return;
}
xlen=xlen-2;
ylen=ylen-2;
int[][] newMatrix=new int[xlen][ylen];
for(int x=0;x<xlen;x++){
for(int y=0;y<ylen;y++){
newMatrix[x][y]=matrix[x+1][y+1];
}
}
fun(newMatrix,list);
}
}
4.矩阵的逆时针旋转
思路:比如有下面2x3的矩阵:
1,2,3
4,5,6
顺时针旋转之后:
3,6
2,5
1,4
发现了一个规律:原来矩阵的行数据在旋转180度的数据在旋转之后变成新矩阵的列数据,比如上边的矩阵 行数据:1,2,3
旋转180度是:3,2,1
逆时针旋转后变为
列数据: 3 2 1
发现规律之后就简单了,我的代码:、
import java.util.ArrayList;
public class Main {
public static int [][] printMatrix(int [][] array) {
if(array==null){
return null;
}
int xlen=array.length;
int ylen=array[0].length;
int[][] newArray=new int[ylen][xlen];
int nxlen=newArray.length;
int nylen=newArray[0].length;
for(int j=0;j<nylen;j++){
for(int i=0;i<nxlen;i++){
newArray[i][j]=array[j][ylen-1-i];
}
}
return newArray;
}
public static void main(String[] args){
int[][] array={{1,2},{3,4},{5,6},{7,8},{9,10}};
array=printMatrix(array);
for(int i=0;i<array.length;i++){
for(int j=0;j<array[0].length;j++){
System.out.println(array[i][j]);
}
}
}
}
几种遍历方式的区别
每个遍历方法的实现原理是什么?
(1)、传统的for循环遍历,基于计数器的:
遍历者自己在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后,停止。主要就是需要按元素的位置来读取元素。
(2)、迭代器遍历,Iterator:
每一个具体实现的数据集合,一般都需要提供相应的Iterator。相比于传统for循环,Iterator取缔了显式的遍历计数器。所以基于顺序存储集合的Iterator可以直接按位置访问数据。而基于链式存储集合的Iterator,正常的实现,都是需要保存当前遍历的位置。然后根据当前位置来向前或者向后移动指针。
(3)、foreach循环遍历:
根据反编译的字节码可以
【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
发现,foreach内部也是采用了Iterator的方式实现,只不过Java编译器帮我们生成了这些代码。
各遍历方式的适用于什么场合?
(1)、传统的for循环遍历,基于计数器的:
顺序存储:读取性能比较高。适用于遍历顺序存储集合。
链式存储:时间复杂度太大,不适用于遍历链式存储的集合。
(2)、迭代器遍历,Iterator:
顺序存储:如果不是太在意时间,推荐选择此方式,毕竟代码更加简洁,也防止了Off-By-One的问题。
链式存储:意义就重大了,平均时间复杂度降为O(n),还是挺诱人的,所以推荐此种遍历方式。
(3)、foreach循环遍历:
foreach只是让代码更加简洁了,但是他有一些缺点,就是遍历过程中不能操作数据集合(删除等),所以有些场合不使用。而且它本身就是基于Iterator实现的,但是由于类型转换的问题,所以会比直接使用Iterator慢一点,但是还好,时间复杂度都是一样的。所以怎么选择,参考上面两种方式,做一个折中的选择。
包含min函数的栈这个问题
剑指offer中包含min函数的栈,借鉴他人优秀的方法
class Solution {
public:
stack stack1,stack2;
void push(int value) {
stack1.push(value);
if(stack2.empty())
stack2.push(value);
else if(value<=stack2.top())
{
stack2.push(value);
}