LeetCode刷题记录(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011024652/article/details/82706037

LeetCode刷题记录(二)

继续数组和字符串卡片的题目,这一篇主要介绍一道二维数组相关的题目。

1、对角线遍历

题目:

这里写图片描述

我的思路:

这一题我的思路比较复杂,我先观察几种类型的二维数组

1、 M=N类型的二维数组,例如:

[1, 2, 3]

[4, 5, 6]

[7, 8, 9]

它的对角线遍历值的索引是:

(0, 1)

扫描二维码关注公众号,回复: 3657273 查看本文章

(0, 1), (1, 0)

(2, 0), (1, 1), (0, 2)

(1, 2), (2, 1)

(2, 2)

2、 对于M< N类型的二维数组,例如:

[0, 1, 2, 3]

[4, 5, 6, 7]

它的对角线遍历值的索引是:

(0, 0)

(0, 1), (1, 0)

(1, 1), (0, 2)

(0, 3), (1, 2)

(1, 3)

3、对于M>N类型的二维数组,例如:

[0, 1]

[2, 3]

[4, 5]

[6, 7]

它的对角线遍历值的索引是:

(0, 0)

(0, 1), (1, 0)

(2, 0), (1, 1)

(2, 1), (3, 0)

(3, 1)

通过比较我们可以发现,第偶数次(从0开始计算)遍历这个数组的对角线的时候,遍历的二维数组的纵向索引是依次变小的,而它的横向索引是依次变大的,第奇数次遍历数组的对角线的时候,它的纵向索引是依次变大的,而它的横向索引是依次变小的。因此我们可以这样做:

  1. 定义两个遍历j和k用于分别表示二位数组的纵向索引和横向索引,它们都是从0开始的;
  2. 依次遍历二维数组的对角线,通过观察,我们可以得到需要遍历M + N - 1次对角线;
  3. 当偶数次遍历对角线的时候,j每次递减1,k每次递增1,依次获得对应索引的数值;
  4. 当奇数次遍历对角线的时候,j每次递增1,k每次递减1,依次获得对应索引的数值。

按照这个思路实现的代码如下:

class Solution {
    public int[] findDiagonalOrder(int[][] matrix) {
        if(null == matrix) {
    		return null;
    	}
        if(matrix.length == 0) {
            return new int[]{};
        } else {
            if(matrix[0].length == 0) {
                return new int[] {};
            }
        }
    	
    	int i = 0, colLen = matrix.length, rowLen = matrix[0].length;
    	int j = 0, k = 0, count = 0;
    	int[] rslt = new int[colLen * rowLen];
    	while(i < colLen + rowLen - 1) {
    		//偶数次j变小,k变大
    		if(i % 2 == 0) {
    			//防止出现索引为负值的情况
    			if(j < 0) {
    				j = 0;
    			} else if(j > colLen - 1) {
    				j = colLen - 1;
    				k++;
    			}
    			if(k < 0) {
    				k = 0;
    			} else if(k > rowLen - 1) {
    				k = rowLen - 1;
    				j++;
    			}
    			
    			while(j >= 0 && k < rowLen && count < rslt.length) {
    				rslt[count] = matrix[j][k];
    				k++;
                    //当k遍历到最大的时候,j不能再减1了,否则下一次将无法从下一位开始
    				if(k < rowLen) {
    					j--;
    				}
    				count++;
    			}
    			i++;
    		}
    		//奇数次j变大,k变小
    		else {
    			if(j < 0) {
    				j = 0;
    			} else if(j > colLen - 1) {
    				j = colLen - 1;
    				k++;
    			}
    			if(k < 0) {
    				k = 0;
    			} else if(k > rowLen - 1) {
    				k = rowLen - 1;
    				j++;
    			}
    			
    			while(j < colLen && k >= 0 && count < rslt.length){
    				rslt[count] = matrix[j][k];
    				j++;
                  	//当j遍历到最大的时候,k不能再减1了,否则下一次将无法从下一位开始
    				if(j < colLen) {
    					k--;
    				}
    				count++;
    			}
    			i++;
    		}
    	}
    	
    	return rslt;
    }
}

反思:

从上面的解法可以看到,这里代码是冗余的,每次遍历对角线的时候都有这样一段代码:

if(j < 0) {
  j = 0;
} else if(j > colLen - 1) {
  j = colLen - 1;
  k++;
}
if(k < 0) {
  k = 0;
} else if(k > rowLen - 1) {
  k = rowLen - 1;
  j++;
}

这是用来判断j和k有没有遍历到最前或者最后,如果遍历到最后需要重置j和k的值以防止出现数组越界的情况。

另外在判断j和k有没有遍历到最后的时候还将另外一个索引加1,这是因为有可能出现j或者k遍历到最后了,但是另一个索引还未到最后的情况,这时候就需要从另一个索引的下一位开始继续遍历,例如:

[1, 2, 3]

[4, 5, 6]

[7, 8, 9]

数组已经遍历到(0, 2)也就是3的时候接下来就需要从6开始遍历了,这时候就需要将j加1,从(1, 2)开始遍历。而之所以每个遍历判断里都增加这个语句主要还是方便理解这段代码用的,完全可以将它们单独抽出来简化代码。

另外在遍历数组中的数的时候,我还增加了一个判断,例如:

if(k < rowLen) {
  j--;
}

或者

if(j < colLen) {
  k--;
}

原先是没有这个判断的,直接使用j–或者k–,这是在测试的时候发现的问题,以下面这个数组为例:

[1, 2, 3]

[4, 5, 6]

[7, 8, 9]

当遍历到(2, 1)即8的时候,这时候j++得到3,k–得到0,跳出循环,再次遍历对角线的时候,j会置为2,k会加1变为1,这时候获取到的仍然是(2, 1),这样仍然得到的是8,这就不正确了,这还是因为k没有向前移一位导致的。因此我增加了一个判断,当j或者k遍历到最大的时候,另一个索引保持不变,以便在下次遍历对角线的时候另一个索引向后移一位。

总的看来,这一道题目我的解法是复杂的,虽然想法比较简单,但是真正运行的时候会出现很多问题,需要仔细考虑才能够真正运行通过,我也会继续寻找更好地解决方案。

猜你喜欢

转载自blog.csdn.net/u011024652/article/details/82706037