力扣刷题之路-数组的旋转、遍历

参考刷题顺序:力扣刷题顺序

涉及题目

189 轮转数组

力扣刷题之路-数组的旋转、遍历
自己的想法: 类似于题目中的解释,一次性的将数字放到最后它应该在的位置,想法和官方的第二个思路差不多,如图。
力扣刷题之路-数组的旋转、遍历
可以看出来,一类的循环(绿色是一类),需要在循环到出现闭合的时候就结束,并且要往后移动一格,再次循环。整个大的循环结束条件很容易判断,就是循环了nums.length次时就可以结束了。此处用count来做算法结束的标志。一个小循环的结束需要判断是否这个循环闭合了,即这个循环是不是又到了循环刚开始的位置,这里的想法是把循环开始的位置的值变成一个标志数,每次一个数值完成了它的移动之后,要判断下一个移动是不是到标志位了。如果到了,那么这个小循环就结束了,如果大循环还没有结束,那么需要新开一个小循环,即需要把标志位往后移动。说起来有点绕。代码也有点乱。感觉看图片其实就很容易理解了。这里把标志设置成-1是偷了个懒。
    public void rotate(int[] nums, int k) {
        int temp=nums[0],temp1;
        int count = 0;
        if(k%nums.length != 0){
            nums[0] = -1;
            for(int i=0;i< nums.length;){
                temp1 = nums[(i+k)%nums.length];
                nums[(i+k)%nums.length] = temp;
                temp = temp1;
                count++;
                if(count >= nums.length) break;
                if(nums[(i+k+k)%nums.length]==-1){
                    nums[(i+k+k)%nums.length] = temp;
                    i = (i+k+k+1)%nums.length;
                    temp = nums[i];
                    count++;
                    if(count==nums.length) break;
                    nums[i] = -1;
                }
                else i = (i+k)%nums.length;
            }
        }
    }

官方的想法: 没看明白第二个环状替换的想法的后边具体是怎么搞的。不过第三个想法感觉很妙。以下图的情况为例,向右移动3个,那么最后三个就会变成最前面的三个,前面的四个就会变成最后的四个。翻转第一次,前后整体变化,翻转第二次,前3个顺序变正,翻转第三次,后四个顺序变正。

力扣刷题之路-数组的旋转、遍历
    public void rotate(int[] nums, int k) {
        reverse(nums,0,nums.length-1);
        reverse(nums,0,k% nums.length-1);
        reverse(nums,k% nums.length, nums.length-1);
    }
    public void reverse(int[] nums,int start,int end){
        while (start<end){ int temp; temp="nums[start];" nums[start]="nums[end];" nums[end]="temp;" start++; end--; } < code></end){>

396 旋转函数

力扣刷题之路-数组的旋转、遍历
自己的想法: 本来的想法是发现不论数组里有几个负数,最大的值都不存在于Bk[0]>Bk[1]的情况。但是一直超时。看到别人的方法是在F0,F1,F2,F3之间找规律,发现F(N)和F(N-1)之间存在一个关系。即F(N)=F(N-1)+A-len(A[len-n])。写的可能不清楚,从F1-F0和F2-F1算一算就可以发现这个规律了。这个题目没有官方题解。这个也算是别人的想法吧
    public int maxRotateFunction(int[] nums) {
        int max=-2147483648;int sum=0,SUMALL=0;
        for(int i = 0;i<nums.length;i++) { sumall +="nums[i];" sum } max="Math.max(max,sum);" for(int i="1;i<=" nums.length;i++){ return max; < code></nums.length;i++)>
  1. 螺旋矩阵

力扣刷题之路-数组的旋转、遍历
自己的想法: 这个题目很容易理解,绕着圈旋转而已。难的是如何界定什么时候往哪里转。被这道题卡了好久。基本的想法就是,每个格子会有四个旋转的方向,判断上下左右的旋转条件就可以。然后用一个标志来判断次数,次数够的时候就停止。
    public List<integer> spiralOrder(int[][] matrix) {
        List<integer> list = new ArrayList<integer>();
        int u = 0,i=0,j=0;
        while (u<matrix.length*matrix[0].length){ list.add(matrix[i][j]); if(i>=matrix[0].length-1-j && j>=(matrix[0].length)/2 && i< matrix.length-(matrix[0].length-j)) i++;//&#x5411;&#x4E0B;
            else if(j>=matrix.length-i && i>=(matrix.length+1)/2 && j<=matrix[0].length-(matrix.length-i)) j--; 向左 else if(j<matrix[0].length-1-i && i<="(matrix.length+1)/2" j>=i-1) j++;//&#x5411;&#x53F3;
            else if(j<(matrix[0].length+1) 2)i--; 向上 u++; } return list; < code></(matrix[0].length+1)></=matrix[0].length-(matrix.length-i))></matrix.length*matrix[0].length){></integer></integer></integer>

官方的想法: 看了看官方的想法好像确实是简单一些。第一个是需要增加一个数组来判断是否被遍历过,这个想法的空间复杂度太高,所以只认真看了第二个按层模拟的想法。按层模拟就是每次的输出是首先输出最外层,然后依次输出里面的一层。设置四个标志位,即左上、左下、右上、右下四个角,按照顺序遍历最外层,遍历完一层之后需要把标志位更新。懒得自己打了,这个题自己做的时候有点太耗心力了,这里粘上官网的代码。

class Solution {
    public List<integer> spiralOrder(int[][] matrix) {
        List<integer> order = new ArrayList<integer>();
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return order;
        }
        int rows = matrix.length, columns = matrix[0].length;
        int left = 0, right = columns - 1, top = 0, bottom = rows - 1;
        while (left <= right && top <="bottom)" { for (int column="left;" column++) order.add(matrix[top][column]); } row="top" + 1; row++) order.add(matrix[row][right]); if (left bottom) -> left; column--) {
                    order.add(matrix[bottom][column]);
                }
                for (int row = bottom; row > top; row--) {
                    order.add(matrix[row][left]);
                }
            }
            left++;
            right--;
            top++;
            bottom--;
        }
        return order;
    }
}

&#x4F5C;&#x8005;&#xFF1A;LeetCode-Solution
&#x94FE;&#x63A5;&#xFF1A;https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode-solution/
&#x6765;&#x6E90;&#xFF1A;&#x529B;&#x6263;&#xFF08;LeetCode&#xFF09;
&#x8457;&#x4F5C;&#x6743;&#x5F52;&#x4F5C;&#x8005;&#x6240;&#x6709;&#x3002;&#x5546;&#x4E1A;&#x8F6C;&#x8F7D;&#x8BF7;&#x8054;&#x7CFB;&#x4F5C;&#x8005;&#x83B7;&#x5F97;&#x6388;&#x6743;&#xFF0C;&#x975E;&#x5546;&#x4E1A;&#x8F6C;&#x8F7D;&#x8BF7;&#x6CE8;&#x660E;&#x51FA;&#x5904;&#x3002;
</=></integer></integer></integer>
  1. 螺旋矩阵 II

力扣刷题之路-数组的旋转、遍历
自己的想法: 这个题目和上边的题目可以说是一模一样。利用上一道题的代码简单修改一下就可以。这里输入的是n,就是说上一道题目中的matrix[0].length和matrix.length是一样的,都是n,把这两个都换成n。然后matrix数组中的元素是从1开始的,所以结束标志u改为从1开始,结束标志改为≤n*n。这样就可以提交了,哈哈哈。做出来一道题等于做出来两道题,感觉非常好。
    public int[][] generateMatrix(int n) {
        int [][] matrix = new int[n][n];
        int u = 1,i=0,j=0;
        while (u<=n*n){ matrix[i][j]="u;" if(i>=n-1-j && j>=(n)/2 && i< j) i++;//&#x5411;&#x4E0B;
            else if(j>=n-i && i>=(n+1)/2 && j<=i) j--; 向左 else if(j<n-1-i && i<="(n+1)/2" j>=i-1) j++;//&#x5411;&#x53F3;
            else if(j<(n+1) 2)i--; 向上 u++; } return matrix; < code></(n+1)></=i)></=n*n){>
  1. 对角线遍历

力扣刷题之路-数组的旋转、遍历
自己的想法: 要被这些个循环折磨疯了。参考前两道题中官方的一个思想,设置left,top,right,bottom作为一次小循环(即一个箭头穿过的值)的开始和结束的标志。这四个标志在一次小循环结束后进行更新,小循环当中的顺序有从下往上或者从上往下,这里也设置一个标志flag作为小循环顺序的标志,因为是从[1][1]开始的,所以刚开始的时候要往左下方进行遍历,这时设置flag=0;一次小循环结束后flag=1,表示下次的循环应该是往右上走。至于四个开始结束标志的更新,可以画几个不同行列数的数组来思考。如下图。
力扣刷题之路-数组的旋转、遍历
画的比较粗糙。总之就是没有到最后一行和最后一列的时候,箭头是往右往下移动,到最后一行的时候是往右移动,到最后一列的时候是往下移动。第一个版本写了个if else来判断数组的行数或者列数是1的情况,这种情况直接遍历输出也可以。后来删除了if else 竟然运行时间还慢了一些。
    public int[] findDiagonalOrder(int[][] mat) {
        int row = mat[0].length,len=mat.length;
        int[] result = new int[row*len];
        int u=0,flag=0;//&#x4ECE;0&#x884C;1&#x5217;&#x5F00;&#x59CB; flag=0&#x8868;&#x793A;&#x5F80;&#x5DE6;&#x4E0B;&#x8D70;&#xFF0C;flag=1&#x8868;&#x793A;&#x5F80;&#x53F3;&#x4E0A;&#x8D70;
        int left=0,right=0,top=0,bottom=0;
        result[0] = mat[0][0];
        while (left<=right && top<="bottom){" if(bottom<len-1 right<row-1){bottom++; right++; } else if(right="=row-1" bottom<len-1){top++;bottom++;} if(bottom="=len-1" right<row-1){left++;right++;} {left++;top++;} if(flag="=" 0){ 向左下走 int i="top,j=right;" while (i<="bottom" j>=left){
                    result[u+1] = mat[i][j];
                    i++;
                    j--;
                    u++;
                }
                flag=1;
            }
            else{//&#x5411;&#x53F3;&#x4E0A;&#x8D70;
                int i=bottom,j=left;//i=2 j=0
                while (i>=top && j<=right){ result[u+1]="mat[i][j];" i--; j++; u++; } flag="0;" return result; < code></=right){></=right>

刷题感想:这两个题目都是中等题,但是其实能把题读明白的话这两个题也不难。感觉想题目的解法的时候不能局限于题目给的解释,比如第一个翻转的题解就很妙。要把眼界打开思考问题。其实还是有点难的。题目太复杂反而有点不想看官方题解了。按照这个刷题顺序来刷确实挺快的!

Original: https://www.cnblogs.com/boboray/p/16219507.html
Author: 啵啵ray
Title: 力扣刷题之路-数组的旋转、遍历

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/685600/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球