【leetcode速通java版】02——有序数组、子数组、螺旋矩阵

简介: 【leetcode速通java版】02——有序数组、子数组、螺旋矩阵

leetcode-T977有序数组的平方


66169a82bccf4540bb30ff97a510e069.png

解法一:暴力破解法

先将数组中的元素遍历变成平方,再进行冒泡排序

class Solution {
    public int[] sortedSquares(int[] nums) {
            for(int i = 0; i < nums.length; i++) {
                nums[i] = nums[i] * nums[i];
            }
            for(int i = 0; i < nums.length; i++) {
                for(int j=i+1; j < nums.length; j++) {
                    if(nums[i] > nums[j]) {
                        int tmp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = tmp;
                    }
                }
            }
            return nums;
    }
}

上面冒泡排序让算法的时间复杂度变成了O(n+n^2),可以换成快速排序。如果您还不知道什么是快速排序,可以参考博客:快速排序

class Solution {
    public int[] sortedSquares(int[] nums) {
            for(int i = 0; i < nums.length; i++) {
                nums[i] = nums[i] * nums[i];
            }
            quickSort(nums, 0, nums.length-1);
            return nums;
    }
    public void quickSort(int[] nums,int left, int right) {
        if(left > right) {
            return;
        }
        int i = left, j = right, base = nums[i];
        while(i != j) {
            while(i<j && nums[j] >= base ) {
                j--;
            }
            while(i<j && nums[i] <= base) {
                 i++;
            } 
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
        nums[left] = nums[i];
        nums[i] = base;
        quickSort(nums, left, i -1);
        quickSort(nums, i + 1, right);
    }
}

上面的时间复杂度是O(n + n*logn).

解法2:双指针法

注意到数组本来是有序的,平方和后,大的数在两边,小的数在中间,可以采用两个指针在两边遍历,把大的数移到另一个新的数组。

class Solution {
    public int[] sortedSquares(int[] nums) {
            for(int i = 0; i < nums.length; i++) {
                nums[i] = nums[i] * nums[i];
            }
            int i = 0;
            int j = nums.length - 1;
            int[] result = new int[nums.length];
            int index = nums.length - 1;
            while(i <= j) {
                if(nums[i] >= nums[j]) {
                    result[index--] = nums[i];
                    i++;
                } else {
                    result[index--] = nums[j];
                    j--;
                }
            }
            return result;
    }   
}

此时的时间复杂度为O(2*n),空间复杂度为O(n),注意到数据的平方操作和排序可以用一次遍历解决,优化如下。

class Solution {
    public int[] sortedSquares(int[] nums) {
            int i = 0;
            int j = nums.length - 1;
            int[] result = new int[nums.length];
            int index = nums.length - 1;
            while(i <= j) {
                if(nums[i] * nums[i] >= nums[j] * nums[j]) {
                    result[index--] = nums[i] * nums[i];
                    i++;
                } else {
                    result[index--] = nums[j] * nums[j];
                    j--;
                }
            }
            return result;
    }
}

总结下:

1.数组的最优解法需要观察数据的特点,比如这道题目的数组元素有两边大,中间小的特点

2.双指针法灵活、高效、好用

leetcode-T209 长度最小的子数组


0ba26740c6ce4aefb54d9782309fbec4.png

法1:暴力解决法

从第一个元素开始遍历数组元素累加,当累加值到达target记录为最小长度。再从第二个元素,第三个元素开始做同样操作,并且不断对比最小长度是否需要进行更新。其时间复杂度为O(n^2),空间复杂度为O(1)

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int minLen = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) { 
            int sum = 0;
            int l = 0;
             for( int j = i;j < nums.length;j++) {
                 sum += nums[j];   
                 l++;
                 if(sum >= target) {
                 // minLen = l < minLen ? l : minLen;
                     if(l < minLen) {
                        minLen = l;
                     }
                     break;
                 }
             }
        }
        // return minLen == Integer.MAX_VALUE ? 0 : minLen;
        if(minLen == Integer.MAX_VALUE) {
            minLen = 0;
        }
        return minLen;
    }
}

法2:滑动窗口法

所谓滑动窗口,就是不断的调整子序列的起始位置和终止位置,从而得出我们想要的结果。其实,滑动窗口法还是一种双指针法。

💐使用滑动窗口法需要确定几点

1.窗口(两个指针)内是什么

2.窗口起始位置(起始指针)怎么移动

3.窗口结束位置(结束指针)怎么移动

我们来回答下。

1.窗口内容就是满足其和>=target的最小树组

2.如果当前窗口满足条件,起始位置就需要向前移动(缩小窗口)

3.窗口的结束指针就是数组的遍历索引。

可以看出,解题的关键就在于窗口的起始位置如何移动?

14c77fe996a044c7aa5e8ef6dedb5b4c.png

其核心逻辑如下。

 while(sum >= target) {
      subLen = j -i + 1;
      minLen = minLen < subLen ? minLen : subLen;
      sum -= nums[i++];
}

来看完整代码。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int minLen = Integer.MAX_VALUE;
        int sum = 0;
        int i = 0;
        int subLen = 0;
        for (int j = 0; j < nums.length; j++) { 
            sum += nums[j];
            while(sum >= target) {
                subLen = j -i + 1;
                minLen = minLen < subLen ? minLen : subLen;
                sum -= nums[i++];
            }
        }
       return minLen == Integer.MAX_VALUE ? 0 : minLen;
    }
}

它的时间复杂度是多少呢?虽然这个方法同样有一个for,一个while,但是每个数组元素只被操作了两次,也就是滑动窗口进来操作了一次,滑动窗口除去操作了一次,时间复杂度是O(n),妙阿。

Leetcode-T59 螺旋矩阵II


811d31cd7cbb4c28a0ca157a019b25d2.png

这道题目其实不涉及太多算法,却能很好的考察思维能力和编程能力。题目中做的事情无非就是对数组进行上、下、左、右四个方向的遍历,遍历要想不重复、不遗漏一定需要有合理的规则。

我们先以三阶矩阵为例子来画下四条边,采取的规则是:左闭右开。

8282aa5a6ff2401aaa5afcd4edb309d0.png

发现没有,定了规则以后就不乱了,三阶矩阵画边就是每个边界走两步。

边画好了,中间填下最后一个数就好了。

这个时候思维再进一步,四阶矩阵要怎么画?

第一步,四阶矩阵先画边。

第二步,剩下的就是一个三阶矩阵。

class Solution {
    public int[][] generateMatrix(int n) {
       int [][] matrix = new int[n][n]; // 定义存储的二维数组
       int start = 0; // 定义起始位置
       int round = 0; // 控制循环次数
       int i,j; // 指针
       int count = 1; // 定义填充数字
       while(round++ < n/2) { 
           // 右
          for(j = start;j < n - round; j++) {
              matrix[start][j] = count++;
          }
           // 下
          for(i = start; i < n - round; i++) {
              matrix[i][j] = count++;
          }
           // 左
            for(; j >= round; j--) {
                matrix[i][j] = count++;
            }
            // 上
            for(; i >= round; i--) {
                matrix[i][j] = count++;
            }
            // 更新起始位置
            start++;
       }
       // n为奇数时,要单独填充最后一个元素
       if(n % 2 == 1) {
         matrix[start][start] = count;
       }
        return matrix;
    }
}


相关文章
|
1月前
leetCode(删除有序数组中的重复项)
如何在不使用额外空间的情况下,通过双指针法原地删除有序数组中的重复项。
33 2
|
3月前
|
存储 Java API
LeetCode------合并两个有序数组(4)【数组】
这篇文章介绍了LeetCode上的"合并两个有序数组"问题,并提供了三种解法:第一种是使用Java的Arrays.sort()方法直接对合并后的数组进行排序;第二种是使用辅助数组和双指针技术进行合并;第三种则是从后向前的双指针方法,避免了使用额外的辅助数组。
LeetCode------合并两个有序数组(4)【数组】
|
1月前
|
C++
Leetcode第54题(螺旋矩阵)
这篇文章介绍了LeetCode第54题“螺旋矩阵”的解题思路和C++的实现代码,该题目要求按照顺时针螺旋顺序返回给定矩阵中的所有元素。
14 1
Leetcode第54题(螺旋矩阵)
|
1月前
【LeetCode 48】108.将有序数组转换为二叉搜索树
【LeetCode 48】108.将有序数组转换为二叉搜索树
38 0
|
1月前
【LeetCode 05】螺旋矩阵II总结
【LeetCode 05】螺旋矩阵II总结
14 0
|
1月前
|
算法 Java
LeetCode(一)Java
LeetCode(一)Java
|
3月前
|
算法
LeetCode第26题删除有序数组中的重复项
这篇文章介绍了LeetCode第26题"删除有序数组中的重复项"的解题方法,通过使用双指针技巧,高效地去除数组中的相邻重复元素。
LeetCode第26题删除有序数组中的重复项
|
3月前
|
算法
LeetCode第80题删除有序数组中的重复项 II
文章介绍了LeetCode第80题"删除有序数组中的重复项 II"的解法,利用双指针技术在O(1)空间复杂度内原地删除重复元素,并总结了双指针技术在处理有序数组问题中的应用。
LeetCode第80题删除有序数组中的重复项 II
|
3月前
|
算法
LeetCode第88题合并两个有序数组
文章分享了LeetCode第88题"合并两个有序数组"的解法,通过从后向前的合并策略避免了数组元素的前移,使用三个指针高效地完成了合并过程。
|
3月前
|
算法
LeetCode第59题螺旋矩阵 II
LeetCode第59题"螺旋矩阵 II"的解题方法,通过模拟螺旋填充过程,一圈一圈从外到内按顺序填充数字,直到完成整个矩阵的构建。
LeetCode第59题螺旋矩阵 II