今日算法题之数组

1. 二分查找(简单)

题目描述:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

二分查找思想

二分查找是一种常用的查找算法,适用于有序数组或有序列表。它的基本思想是将查找区间逐渐缩小为一半,直到找到目标元素或确定目标元素不存在。

具体实现思路如下:

  1. 确定查找区间的起始位置和结束位置,通常为数组或列表的首尾元素索引。
  2. 计算查找区间的中间位置 mid = (start + end) / 2。
  3. 比较中间位置的元素与目标元素的大小关系:
    • 如果中间位置的元素等于目标元素,则找到目标元素,返回结果。
    • 如果中间位置的元素大于目标元素,则目标元素可能在左半部分,将结束位置更新为 mid - 1,继续执行步骤 2。
    • 如果中间位置的元素小于目标元素,则目标元素可能在右半部分,将起始位置更新为 mid + 1,继续执行步骤 2。
  4. 重复步骤 2 和步骤 3,直到找到目标元素或确定目标元素不存在。

二分查找的时间复杂度是 O(logN),其中 N 是查找区间的大小。由于每次查找都将查找区间缩小为一半,因此它的效率非常高。但前提是要求查找的数据结构是有序的

class Solution {
    public int search(int[] nums, int target) {
        if(target<nums[0]||target>nums[nums.length-1]){
            return -1;
        }
        int left=0;
        int right=nums.length-1;
        int mid=0;
        while(left<=right){
            mid=(right+left)/2;
            if(nums[mid]<target){
                left=mid+1;
            }else if(nums[mid]>target){
                right=mid-1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

2. 移除元素(简单)

题目描述:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

 首先,数组元素在内存地址中存储是连续的。不能删除单个元素,只能进行覆盖。

所以本次我们采用快慢指针法,快的指针(right)负责判断数组元素是否等于目标值,慢的指针(solw)负责覆盖目标值。时间复杂度O(n),空间复杂度O(1).

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

3. 有序数组的平方(简单)

题目描述:

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

暴力排序法: 首先我们可以使用暴力排序的方式来解决这道题,先将数组内的元素进行平方,然后对数据进行排序。

class Solution {
    public int[] sortedSquares(int[] nums) {
        for(int i=0;i<nums.length;i++){
            nums[i]=nums[i]*nums[i];
        }

        Arrays.sort(nums);
        return nums;
    }
}

双指针排序法 : 因为数组元素是非递减的有序数组,所以元素平方最大值一定是在数组两边,所以我们可以使用双指针法,在数组第一位(left)和最后一位(right)将数组平方后进行对比,如果 left大,则left向前进一位,如果right大,则right向后退一步。

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

4. 长度最小的子数组(中等)

题目描述 : 

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

 滑动窗口 : 滑动窗口就是不断的调节序列的起始位置和终止位置,从而达到想要的结果。

首先都是r是快指针,l是慢指针。当r走到一定程度时达到了某种条件,此时用一个数result将r和l之间的距离存储起来,然后此时l开始向前进一步,如果此时l和r没有达到条件,则r向前进,直到达到条件。然后再将此时的r与l之间的距离与result相比较。从而达到获取长度最小的子数组。

AK代码

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
         int l=0;
         int sum=0;
         int result=Integer.MAX_VALUE;
         for(int r=0;r<nums.length;r++){
             sum+=nums[r];
             while(target<=sum){
                 result=Math.min(result,r-l+1);
                 sum -=nums[l];
                 l++;
             }
         }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

在本次代码中有一些语句

Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
Integer.MIN_VALUE表示int数据类型的最小取值数:-2 147 483 648
 

Integer.MAX_VALUE ? 0 : result;

(关系表达式) ? 表达式1 : 表达式2;   //与上面的语句对应

而该代码则是 如果result不等于Integer.MAX_VALUE,则输出result

示例:

int x = 10;
int y = 5;
int z;
如果x大于y 则是true,将x赋值给z;
如果x不大于y 则是false,将y赋值给z;
z = (x > y) ? x : y;

5.  螺旋矩阵(中等)

题目描述:

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

 

class Solution {
    public int[][] generateMatrix(int n) {
int loop = 0;  // 控制循环次数
        int[][] res = new int[n][n];
        int start = 0;  // 每次循环的开始点(start, start)
        int count = 1;  // 定义填充数字
        int i, j;

        while (loop++ < n / 2) { // 判断边界后,loop从1开始
            // 模拟上侧从左到右
            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;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_55347789/article/details/131933937