zl程序教程

您现在的位置是:首页 >  后端

当前栏目

数组专题~有人十八单手开法拉利,有人二十加在lc刷算法题

算法数组 专题 十八 二十 有人 LC
2023-09-14 09:16:17 时间

第一题:力扣977题:有序数组的平方

解法一:暴力解法

class Solution {
    public int[] sortedSquares(int[] nums) {
        //先计算
        for(int i = 0; i < nums.length; i++) {
            nums[i] *= nums[i];
        }
        //再排序
        Arrays.sort(nums);
        return nums;
    }
}

解法二:双指针

Q1:为什么会想到双指针呢?
A1:因为给的数组本身是一个非递减的数组,最小负数和最大正数应该分布在数组的两端,所以适合双指针。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int k = nums.length-1;
        //定义一个大小和nums相同的数组
        int[] result = new int[nums.length];
        
        //前后比较,移动指针
        for(int i = 0, j = nums.length - 1; i <= j;) {
            if(nums[i] * nums[i] >= nums[j] * nums[j]) {
                result[k--] = nums[i] * nums[i];
                i++;
            } else if(nums[i] * nums[i] < nums[j] * nums[j]) {
                result[k--] = nums[j] * nums[j];
                j--;
            }
        }
        return result;
    }
}

第二题:力扣209题:长度最小的子数组

解题思路:

经典的滑动窗口问题,大概思想就是不断记录窗口的长度,因为要求的是最小窗口,然后以数组开端为窗口开端,不断往后加,直到窗口内的数之和大于等于目标数,我们就开始往外减(也就是开始缩小窗口,窗口开端往右移动),最终从窗口右端到达数组最右端,结束。

代码如下:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //滑窗的开端
        int i = 0;
        //窗口总和
        int sum = 0;
        //定义一个最大长度
        int result = Integer.MAX_VALUE;
        //滑窗的末端
        for(int j = 0; j < nums.length; j++) {
            sum += nums[j];
            //窗口内部缩小开端
            while(sum >= target) {
                //记录最小窗口
                int subLen = j - i + 1;
                result = result < subLen ? result : subLen;
                sum -= nums[i];
                i++;
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

第三题:力扣904题:水果成篮

解题思路:

此题为滑动窗口系列中的计数问题,fruitFrequence数组记录现在窗口中每种水果的数目,count记录现在窗口中有多少种不同的水果,如果count<=2,那么right指针可以一直向右移动,直到count>2,当count>2时,说明窗口中的水果种类超过2,为了减少水果种类,left指针就要向右移动,移动的同时还要更新fruitFrequence数组,最后取最大值即可。

代码如下:

class Solution {
    public int totalFruit(int[] fruits) {
        int n = fruits.length;
        if (n <= 2){
            return n;
        } 
        int total = 2;
        int left = 0;
        // 计算篮中种类数
        int count = 0; 
        // 计算篮中每种水果出现的次数
        int[] fruitFrequence = new int[n]; 
        for (int right = 0; right < n; right++) {
            fruitFrequence[fruits[right]] += 1; // 入篮
            //等于1说明第一次入篮,count需要加1
            if (fruitFrequence[fruits[right]] == 1) {
                count+=1; 
            } 
            // 篮中超过两种水果
            while (count > 2) { 
                fruitFrequence[fruits[left]] -= 1;
                // 等于0说明篮中已经没有fruits[left]水果,count减1
                if (fruitFrequence[fruits[left]] == 0) count-=1; 
                // 移动left
                left += 1; 
            }
            // 取窗口最大值
            total = Math.max(total, right - left + 1); 
        }
        return total;
    }
}

第四题:力扣59题:螺旋矩阵 II

解题思路:

由外圈向里圈顺时针转,一条边一条边的进行处理,注意的是有奇数和偶数的区别,奇数需要特殊处理。

代码如下:

class Solution {
    public int[][] generateMatrix(int n) {
        //定义一个新数组
        int[][] res = new int[n][n];
        //计算一下循环的圈数
        int loop = n / 2;
        //定义起点位置坐标
        int startX = 0;
        int startY = 0;
        //定义控制变量
        int control = 1;
        //定义填充内容
        int count = 1;
        //定义奇数时 中间 坐标(需要单独处理)
        int mid = n / 2;
        //转圈圈
        while(loop > 0) {
            int i = startX;
            int j = startY;
            //上层,从左到右
            for( ; j < startY + n - control; j++) {
                res[startX][j] =  count;
                count++;
            }
            //右层,从上到下
            for( ; i < startX + n - control; i++) {
                res[i][j] = count;
                count++;
            }
            //下层, 从右到左
            for( ; j > startY; j--) {
                res[i][j] = count;
                count++;
            }
            //左层, 从下到上
            for( ; i > startX; i--) {
                res[i][j] = count;
                count++;
            }
            //转完一圈之后,更新转圈的条件
            startX += 1;
            startY += 1;
            control += 2;
            loop--;
        }
        //单独处理奇数情况下的中间数
        if(n % 2 == 1) {
            res[mid][mid] = count;
        }
        return res;
    }
}

第五题:力扣54题:螺旋矩阵

解题思路:

和 第四题:力扣59题 非常类似,都是逐层去解题的,由外至里。确定好四个角的坐标即可,其实代码有好多种,但是万变不离其中,顺着自己的思路写就行。

代码如下:

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> res = new ArrayList<>();
        //定义好 坐标位置
        int rows = matrix.length;
        int columns = matrix[0].length;
        int up = 0;
        int down = rows - 1;
        int left = 0;
        int right = columns - 1;
        
        while(left <= right && up <= down) {
            //上行,从左往右
            for(int column = left; column <= right; column++) {
                res.add(matrix[up][column]);
            }
            //右行,从上往下
            for(int row = up + 1; row <= down; row++) {
                res.add(matrix[row][right]);
            }
            
            if(left < right && up < down) {
                //下行,从右往左
                for(int column = right - 1; column >= left; column--) {
                    res.add(matrix[down][column]);
                }
                //左行,从下往上
                for(int row = down - 1; row >= up + 1; row--) {
                    res.add(matrix[row][left]);
                }
            }
            left++;
            right--;
            up++;
            down--;
        }
        return res;
    }
}

第六题:力扣27题:移除元素

解法一:暴力法

class Solution {
    public int removeElement(int[] nums, int val) {
        int length = nums.length;
        for(int i = 0; i < length; i++) {
            if(nums[i] == val) {
                for(int j = i + 1; j < length; j++) {
                    nums[j-1] = nums[j];
                }
                i--;
                length--;
            }
        }
        return length;
    }
}

解法二:双指针法

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        for(int fast = 0; fast < nums.length; fast++) {
            if(nums[fast] != val) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
}

第七题:力扣26题:删除有序数组中的重复项

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums.length == 0) {
            return 0;
        }
        int slow = 1;
        for(int fast = 1; fast < nums.length; fast++) {
            if(nums[fast] != nums[fast-1]) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
}

第八题:力扣283题:移动零

class Solution {
    public void moveZeroes(int[] nums) {
        //快慢指针 去除0
        int slow = 0;
        for(int fast = 0; fast < nums.length; fast++) {
            if(nums[fast] != 0) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //除去0之后的全部补0
        for(int i = slow; i < nums.length; i++) {
            nums[i] = 0;
        }
    }
}

第九题:力扣844题:比较含退格的字符串

最后这个题解是在官方题解下边粘过来的,我感觉写的很详细了,大家可以参考一下哈!!!

class Solution {
    public boolean backspaceCompare(String s, String t) {
        int sN = s.length(), tN = t.length();
        int i = sN - 1, j = tN - 1;
        int skipS = 0, skipT = 0;
        while (i >= 0 || j >= 0)
        {
            // 先找到 s 中第一个需要比较的字符(即去除 # 影响后的第一个待比较字符)
            while (i >= 0)
            {
                if (s.charAt(i) == '#')
                {
                    skipS ++;
                    i --;
                }
                else if (skipS > 0)
                {
                    skipS --;
                    i --;
                }
                else
                {
                    break;
                }
            }
            // 再找到 t 中第一个需要比较的字符(即去除 # 影响后的第一个待比较字符)
            while (j >= 0)
            {
                if (t.charAt(j) == '#')
                {
                    skipT ++;
                    j --;
                }
                else if (skipT > 0)
                {
                    skipT --;
                    j --;
                }
                else
                {
                    break;
                }
            }
            // 然后开始比较,注意有下面这个 if 条件的原因是:如果 index = 0 位置上为 '#',则 i, j 会为 -1
            // 而 index = -1 的情况应当处理。
            if (i >= 0 && j >= 0) 
            {
                // 如果待比较字符不同,return false
                if (s.charAt(i) != t.charAt(j))
                    return false;
            }
            // (i >= 0 && j >= 0) 为 false 情况为
            // 1. i < 0 && j >= 0
            // 2. j < 0 && i >= 0
            // 3. i < 0 && j < 0
            // 其中,第 3 种情况为符合题意情况,因为这种情况下 s 和 t 都是 index = 0 的位置为 '#' 而这种情况下
            // 退格空字符即为空字符,也符合题意,应当返回 True。
            // 但是,情况 1 和 2 不符合题意,因为 s 和 t 其中一个是在 index >= 0 处找到了待比较字符,另一个没有找到
            // 这种情况显然不符合题意,应当返回 False,下式便处理这种情况。
            else if (i >= 0 || j >= 0)
                return false;
            i--;
            j--;
        }
        return true;
    }
}