【力扣】数组专题

在跟随代码随想录刷题的过程中,完成数组部分的相关题目,所以在此进行一个小总结。

本篇笔记涉及的力扣题目如下:【可以使用Ctrl+F进行搜索~】

  1. 704. 二分查找
  2. 27. 移除元素
  3. 977. 有序数组的平方
  4. 209. 长度最小的子数组
  5. 59. 螺旋矩阵 II
  6. 15. 三数之和
  7. 18. 四数之和

数组相关问题的一点小总结

  1. 使用二分法对有序的数组进行元素查找,能够提高查找效率
  2. 对于数组问题,可采用快慢指针进行相关操作

题目:704. 二分查找

解题思路

  • 思路:给定一个nums数组,注意数组是升序排列的;那么,找到当前target元素是否存在于数组之中,可采用二分法查找
  • 使用left指向数组头,right指针指向数组尾,mid用于计算二分查找的位置,mid=left+(right-left)/2,避免由于left和right过大导致计算结果溢出的现象
  • 如果当前nums[mid]比target大,那么就往左边找;反之,则向右边找;如果相等,说明找到了,返回当前的mid值即可
  • 结束条件,当前的left移动到了right的右边,则说明两指针之间已不存在元素,则返回-1即可

Java代码实现

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;

        while(left <= right) {
            int mid = left + (right-left)/2;
            if(nums[mid] > target) {
                right = mid - 1;
            } else if(nums[mid] < target) {
                left = mid + 1;
            } else {
                return mid;
            }
        }

        return -1;
    }
}

参考资料:704. 二分查找


题目:27. 移除元素

解题思路

  • 给定一个数组,以及一个需要删除的值;要求在O(1)的空间复杂度中完成
  • 可考虑采用快慢指针的方式,left用于记录当前需要进行替换的元素,right指针用于遍历整个数组
  • 当right指针所指的值 是 删除元素 时,那么right右移,left不动即可
  • 若不是,那么将right所指值赋值给left即可
  • 当left和right指向同一位置是否有影响?当前right所指值不需要删除,所以将right所指位置的值赋值给left,即将当前位置的元素赋值给当前元素,自己替换自己,不影响结果。

Java代码实现

class Solution {
    public int removeElement(int[] nums, int val) {
        if(nums == null || nums.length == 0){
            return 0;
        }

        int left = 0;
        for(int right=0; right<nums.length; right++) {
            if(nums[right] != val) {
                nums[left] = nums[right];
                left++;
            }
        }

        return left;
    }
}

参考资料:27. 移除元素


题目:977. 有序数组的平方

解题思路

  • 给定一个非递减序列的数组,要求返回每个数字的平方,且按照非递减序列排序;观察数组可知,一个数进行平方之后,最大值只能出现在数组头或数组尾,因而比较两位置的平方后填入res数组中即可
  • 设置双指针,left指向头,right指向尾;将结果按照从大到小的顺序倒序放在res中即可
  • 如果将left所指值的平方,放在res中,那么将left右移;否则,将right左移
  • 需要注意的是,如果使用Math.pow函数,其返回值是double类型,需要将其类型转化为int类型

Java代码实现

class Solution {
    public int[] sortedSquares(int[] nums) {
        int len = nums.length;
        int[] res = new int[len];
        int left = 0;
        int right = len-1;

        for(int i=len-1; i>=0; i--) {
            // if(nums[left] * nums[left] > nums[right] * nums[right]) {
            //     res[i] = nums[left] * nums[left];
            //     left++;
            // } else {
            //     res[i] = nums[right] * nums[right];
            //     right--;
            // }
            res[i] = Math.abs(nums[left]) > Math.abs(nums[right]) ? (int) Math.pow(Math.abs(nums[left++]), 2) : (int) Math.pow(Math.abs(nums[right--]), 2);
        }

        return res;
    }
}

参考资料

  1. 有序数组的平方.双指针法
  2. Java pow() 方法

题目:209. 长度最小的子数组

解题思路:

  1. 初始化最小长度,设置为最大值,当最小长度变小时,该值更新
  2. 设置left和right指针,left指针用于记录左边界,当求和sum大于target时,左指针右移;right指针记录右边界,当求和sum小于target时,右指针右移,继续寻找符合要求的子字符串。
  3. 当右边界符合题目要求时,更新最小长度minLength

Java代码实现

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int res = Integer.MAX_VALUE;
        int left = 0;
        int right = 0;
        int temp = 0;

        while(right < nums.length){
            temp += nums[right];
            while(temp >= target) {
                res = Math.min(res, right - left + 1);
                temp -= nums[left];
                left++;
            }
            right++;
        }

        return res==Integer.MAX_VALUE ? 0 : res;
    }
}

参考资料:209.长度最小的子数组


题目:59. 螺旋矩阵 II

解题思路

  1. 手动模拟螺旋矩阵,分别实现四个方向的代码,将数组依次填入数组中即可
  2. 需要注意的是,如果n为奇数,说明最后只剩下中间的一个位置,将最后一个数直接填入即可;若n为偶数,则正好能够遍历n/2遍

Java代码实现

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        int count = 1;
        int start = 0;
        int loop = 0;
        int i, j;

        while(loop++ < n/2) {
            for(j=start; j<n-loop; j++) {
                res[start][j] = count++;
            }

            for(i=start; i<n-loop; i++) {
                res[i][j] = count++;
            }

            for(; j>=loop; j--) {
                res[i][j] = count++;
            }

            for(; i>=loop; i--) {
                res[i][j] = count++;
            }
            start++;
        }

        if(n % 2 == 1) {
            res[start][start] = count;
        }

        return res;
    }
}

参考资料:59. 螺旋矩阵 II


题目: 15. 三数之和

解题方法

  • 思路:将数组按照从小到大的顺序排列,使用双指针法;依次判断三数之和是否等于0,若不等于,则尝试通过移动指针使其符合要求。需要注意:去重操作
  • 定义一个ArrayList用于存放结果
  • 将数组从小到大排序,此时遍历一遍数组即可
  • 分别定义i, left, right三个指针,分别指向当前元素,当前元素的下一个,以及最后一个元素
  • 使用sum记录三数之和,若sum>0表示三数之和较大,故需要减小最大值,即将right--;同理,sum<0,left++

Java代码实现

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        // 创建一个result数组,用于记录结果
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0; i<nums.length; i++){
            // 排序后数组的第一个元素大于0,则不存在相加为0的三元组
            if(nums[i] > 0){
                return result;
            }
            /*
            去重操作:若nums[i-1]==nums[i]
            表示nums[i-1]与其他的元素构成的三元组与nums[i]构成的相同【存在重复三元组】
            e.g. 示例一:nums = [-1,0,1,2,-1,-4]
            排好序后nums = [-4,-1,-1,0,1,2]
            -1   + 0 + 1 = 0
               -1+ 0 + 1 = 0
             */
            if(i>0 && nums[i-1]==nums[i]){
                continue;
            }
            
            int left=i+1, right=nums.length-1;
            int sum,temp; //sum记录总和,判断是否等于0;temp记录i+right值
            while(left < right){
                sum = nums[i] + nums[left] + nums[right];
                // sum>0表示三数之和较大,故需要减小最大值,即将right--;同理,sum<0,left++
                if(sum > 0){
                    right--;
                } else if(sum < 0){
                    left++;
                } else {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    // 对b和c去重,若right和right-1所指的值相同,则将right--,即跳过right-1
                    while(right>left &&nums[right] == nums[right-1]){
                        right--;
                    }
                    while(right>left &&nums[left] == nums[left+1]){
                        left++;
                    }
                    right--;
                    left++;
                }
            }
        }
        return result;
    }
}

参考资料:

  1. 15. 三数之和
  2. Java ArrayList
  3. Arrays.asList() 详解

题目:18. 四数之和

解题思路

  • 思路和上述15. 三数之和相同
  • 使用四个指针,i, j, left, right;i从0开始,j=i+1,left=j+1,right=nums.length-1
  • 首先确定i和j,移动left和right,确定四元组;left从前向后移动,right从后向前移动
  • 遍历完成数组一遍后,将i, j后移,重复上述过程
  • 题目要求,需要取出重复的四元组,所以在i,j开始遍历前,判断当前的i, j是否和前一个元素相同,进行去重【continue】;在找到一个四元组后,对left和right所指元素进行去重操作【移动指针】

Java代码实现

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);

        for(int i=0; i<nums.length; i++){
            if(nums[i]>0 && nums[i]>target){
                return result;
            }

            // 对i去重
            if(i>0 && nums[i-1] == nums[i]){
                continue;
            }

            for(int j=i+1; j<nums.length; j++){
                // 对j去重
                if(j>i+1 && nums[j-1] == nums[j]){
                    continue;
                }
                int left=j+1, right=nums.length-1;
                while(left<right){
                    long sum;
                    sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if(sum > target){
                        right--;
                    } else if(sum<target){
                        left++;
                    } else {
                        result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        
                        // 对left和right进行去重
                        while(left<right && nums[right-1] == nums[right])  right--;
                        while(left<right && nums[left+1] == nums[left])    left++;
                        
                        right--;
                        left++;
                    }
                }     
            }
        }
        return result;
    }
}

参考资料:18. 四数之和

posted @ 2023-05-18 14:45  是你亦然  阅读(57)  评论(0)    收藏  举报