[LeetCode]-模拟

前言

记录刷 LeetCode 时遇到的模拟相关题目

59.螺旋矩阵 II

这道题通过循环从外到里处理矩阵的一行一列,共有四个循环,形式上都是一样的,边界条件很多,这时我们就要注意 循环中遵循“不变量” 的原则,每一次行的遍历都要按照一定的规则来遍历

public int[][] generateMatrix(int n) {
    if(n == 1){
        return new int[][]{{1}};
    }
    int[][] matrix = new int[n][n];
    int time = n - 1;
    int row = 0;
    int column = 0;
    int num = 1; //用num表示每次要填入的数字
    int end = n * n + 1; 
    while (num != end){
    	//这里四个循环代表了矩形的四条边,每一条边都采用左闭右开的方式
    	//进行遍历,所以每一次循环都要执行n-1次,用i来作为计数器
    	//num最大只能到 n*n,由于使用的是num++,所以当num到达n*n+1时,矩阵中所有数字均已填入
        for(int i = 1;i <= time && num != end;i++){
            matrix[row][column++] = num++;
        }
        for(int i = 1;i <= time && num != end;i++){
            matrix[row++][column] = num++;
        }
        for(int i = 1;i <= time && num != end;i++){
            matrix[row][column--] = num++;
        }
        for(int i = 1;i <= time && num != end;i++){
            matrix[row--][column] = num++;
        }
        //最左边赋值完后要让指针回到下一个最顶边进行新一轮的赋值
        row++;
        column++;
        //如果本次循环中每一条边都赋值两个元素,说明下一次循环只剩最后一个中心点需要赋值,此时time不能减2而应该是等于1
        time = time == 2 ? 1 : time - 2;
    }
    return matrix;
}

54.螺旋矩阵

上面的 59 题会做,这道题思路基本上是一样的

public List<Integer> spiralOrder(int[][] matrix) {
    List<Integer> result = new ArrayList<>();
    //处理矩阵只有一行的特例
    if(matrix.length == 1){
        for (int i = 0; i < matrix[0].length; i++) {
            result.add(matrix[0][i]);
        }
        return result;
    }
    int rowLength = matrix.length;
    int columnLength = matrix[0].length;
    //row跟column记录当前访问的元素
    int row = 0;
    int column = 0;
    //numCount表示一共需要访问多少个元素
    int numCount = (rowLength) * (columnLength);
    //count记录当前已经访问过了多少个元素
    int count = 0;
    //循环条件是档期按已经访问过的元素个数小于一共需要访问的个数
    while (count < numCount){
    	//这个if分支是应对遍历到最后只剩最后一个元素(矩阵正中间)时的情况
    	//对于[[1,2,3],[4,5,6],[7,8,9]]这个样例,如果没有这个if分支,按照1->2->3->6->9->8->7->4的顺序执行完一个最外层的while后,此时rowLength跟columnLength都为1,再次进入while后会死循环
        if(currentCount + 1 == numCount){
            result.add(matrix[row][column]);
            count++;
        }
        //采取左闭右开的访问规则,即每一行/列的最后一个元素留到作为下一个列/行的第一个元素再访问
        for(int i = 1;i <= columnLength - 1 && count < numCount;i++){
            result.add(matrix[row][column++]);
            count++;
        }
        for(int i = 1;i <= rowLength - 1 && count < numCount;i++){
            result.add(matrix[row++][column]);
            count++;
        }
        for(int i = 1;i <= columnLength - 1 && count < numCount;i++){
            result.add(matrix[row][column--]);
            count++;
        }
        for(int i = 1;i <= rowLength - 1 && count < numCount;i++){
            result.add(matrix[row--][column]);
            count++;
        }
        row++;
        column++;
        rowLength -= 2;
        columnLength -= 2;
    }
    return result;
}

867. 转置矩阵

根据矩阵转置的定义,利用 res[j][i] = matrix[i][j] 进行模拟转置即可

public int[][] transpose(int[][] matrix) {
    introw = matrix.length;
    int column = matrix[0].length;
    int[][] res = new int[column][row];
    for(int i = 0;i < row;i++){
        for(int j = 0;j < column;j++){
            res[j][i] = matrix[i][j];
        }
    }
    return res;
}

66. 加一

从低位往高位按位模拟加法即可,要注意的是可能会产生进位

  1. 根据题意,首位是 0 的话 digits 表示的就是 0,直接返回 1
  2. 如果最低位小于 9,那就直接加一然后返回,如 [1,8,8],直接返回 [1,8,9]
  3. 如果最低位等于 9,那就加一进位,进位后可以被进的高一位也要进位,所以要一直进位到出现进位完小于等于 9 的位,
  4. 或者一直进位到最高位然后最左边补个 1,如 [1,9,9],进位进到 1,得到 [2,0,0];又如 [9,9,9],进位完最左边要多补一位,得到 [1,0,0,0]
public int[] plusOne(int[] digits) {
    if(digits[0] == 0) return new int[]{1};
    int len = digits.length;
    if(digits[len - 1] < 9){
        digits[len - 1] += 1;
        return digits;
    }
    int index = len - 1;
    digits[index] = 10;
    while(digits[index] > 9){
        digits[index--] = 0;
        //已经进到最高位了,所以多补一个最高位的1
        if(index == -1){
            int[] ans = new int[len + 1];
            ans[0] = 1;
            System.arraycopy(digits,0,ans,1,len);
            return ans;
        }
        digits[index] += 1;
    }
    return digits;
}

498. 对角线遍历

根据示意图可以看出,对角线遍历的路径为,从 [0,0] 开始,先沿从左下角到右上角的方向遍历,当遍历到边界时,遍历下一条对角线,然后沿从右上角到左下角的方向遍历,当遍历到边界时,继续换到下一条对角线,遍历方向改为从左下角到右上角,以此类推

指针 i,j 指向当前遍历的元素横纵坐标,flag 变量标记当前的遍历方向,为 true 时从左下角到右上角,否则相反
那么当 flag 为 true 时,i,j 的变化应该是 i--,j++,当然在变化前要判断变化后的值是否还在矩阵范围内。如果变化后会超出范围,就不能变化,而且说明要遍历下一条对角线了。由于遍历起点为 [0,0],所以为了遍历下一条对角线,j 需要尝试加一指向同一行下一列的那个元素,如果 j + 1 不在矩阵范围,说明已经遍历到了最长的那条对角线,为了遍历下一条对角线,此时需要指向同一列的下一行的那个元素,即 i++。另外一个方向上的操作同理,不再赘述:

public int[] findDiagonalOrder(int[][] mat) {
    boolean flag = true;
    int i = 0,j = 0,m = mat.length,n = mat[0].length,index = 0,count = m * n;
    int[] res = new int[count];
    while(index < count){
        res[index++] = mat[i][j];
        if(flag){   //从左下角到右上角的方向
            if(i - 1 >= 0 && j + 1 < n){
                i--;
                j++;
            }else{
                flag = false;
                if(j + 1 >= n) i++;
                else j++;
            }
        }else{   //从右上角到左下角的方向
            if(i + 1 < m && j - 1 >= 0){
                i++;
                j--;
            }else{
                flag = true;
                if(i + 1 >= m) j++;
                else i++;
            }
        }
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值