leecode_数组

滑动窗口思想

其主要思想就是用两个指针来确定题目中所要求的范围。主要要求三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置
  • 如何移动窗口的结束位置

窗口就是满足其合小于target的长度最小的连续子数组
窗口的起始位置如何移动:如果窗口的值大于等于target了,窗口就要向前移动了(也就是该缩小了)
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引

解题的关键就是窗口的起始位置如何移动?

​ 此代码就是动态调节滑动窗口的起始位置

while(sum>=s){  //  这里使用while,
    // 每次更新left位置,并不断比较子序列是否符合条件
    result = Math.min(result,right-left+1);
    sum-=nums[left++];  //不断调整起始位置
}

可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置,将时间复杂度将为o(n)

数组计算前缀和

**前缀和算法(Prefix Sum)**是一种用于快速计算数组元素之和的技术。它通过预先计算数组中每个位置前所有元素的累加和,将这些部分和存储在一个新的数组中,从而在需要计算某个区间的和时,可以通过简单的减法操作得到结果,而不必重新遍历整个区间。

1、子数组和的计算:通过前缀和,可以快速计算任意子数组的和,从而解决一系列相关问题,如最大子数组和、最小子数组和等。

2、区间和的查询:如果需要频繁查询某个区间的和,可以利用前缀和提前计算出所有区间的和,并存储在辅助数组中,以实现快速查询。

3、数组元素更新:当数组中的元素需要频繁更新时,通过前缀和可以减少更新的时间复杂度,提高算法效率

双指针思想

快慢指针思想:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

双指针方法适用于字符串,列表等能直接访问的数据结构,且有序。让两个指针从快慢或头尾分别遍历,使之满足条件

原地哈希

原地哈希用来解决这样一种问题:需要一个使得数组尽量有序的方式,并且要求[时间复杂度]达到O(n)。

原地哈希就相当于,让每个数字n都回到下标为n-1的位置。那些没有找到位置的元素要么1.小于0或者大于数组的最大范围 2.出现了重复。
这些数组被放置在i的位置上是因为元素i+1的缺失。因此需要构建原地哈希来找出重复或者消失的元素。

其中,主要代码为nums[nums[i] - 1] != nums[i],即nums[i]是否在其应该在的位置nums[nums[i]-1]上。如果不在则进行交换。如果在,比较

nums[nums[i]-1]和nums[i]如果相同,则表明重复。

leecode977
public class leecode977 {
    //给你一个按 非递减顺序 排序的整数数组 nums,
    // 返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
    public static void main(String[] args) {
        int[]nums ={-4,-1,0,3,10};
        sortedSquares_01(nums);
    }
    public int[] sortedSquares(int[] nums) {
        /**
         * 题解:方法一,直接排序
         *   1.遍历数组并平方
         *   2.排序
         */
        int []ans =new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            ans[i] = nums[i] * nums[i];
        }

        Arrays.sort(ans);
        return ans;
    }
    public static int[] sortedSquares_01(int[] nums){
        /*
        方法二:双指针
          1.先将数组平方
          2.设两个左右指针,并开始比较大小
          3.将大的放入最后,直到结束
         */
        int len = nums.length;
        int i = 0,j = len - 1;
        int []ans = new int[len];
        for(int p = len - 1;p>=0;p--){
            int left = nums[i]*nums[i];
            int right = nums[j]*nums[j];

            if(left > right){
                ans[p] = left;
                i++;
            }else{
                ans[p] = right;
                j--;
            }
        }
        return ans;
    }
}

此题应用了双指针这一经典算法,从两边往中间遍历排序。

leecode_27
public class leeCode27 {
    //给你一个数组 nums 和一个值 val,
    // 你需要 原地 移除所有数值等于 val 的元素。
    // 元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
    public int removeElement(int[] nums, int val) {
        /**
         * 题解:
         *   将与val值不相同的元素放入原来的数组中
         */
        int k = 0;
        for(int x:nums){
            if(x!=val){
                nums[k++] = x;
            }
        }
        return k;
    }
}
leecode_209
private int minSubArrayLen_01(int s,int[] nums){
        int left = 0;  //滑动窗口起始位置
        int sum = 0;  //滑动窗口数值之和
        int result = Integer.MAX_VALUE;

        for(int right = 0;right < nums.length;right++){
            sum+=nums[right];
            while(sum>=s){  //  这里使用while,
                // 每次更新left位置,并不断比较子序列是否符合条件
                result = Math.min(result,right-left+1);
                sum-=nums[left++];
            }
        }
        //如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == Integer.MAX_VALUE?0:result;
    }
leecode_442
public class leecode442 {
    /*
    给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。
    请你找出所有出现 两次 的整数,并以数组形式返回。
     */
    public List<Integer> findDuplicates(int[] nums) {
        /**
         * 思想:
         *   原地哈希,对于值为k的数字,他应该出现的位置为k-1
         *
         *   从前往后遍历nums,并尝试处理num[i]放到目标位置num[i]-1处
         * 如果发现
         */
        List<Integer> ans = new ArrayList<>();
        int len = nums.length;
        for (int i = 0; i < len; i++) {
            int t = nums[i];
            if(t<0||t-1 == i) continue;  //数据小于0或者本身就在原来的位置上
            if(nums[t-1] == t){
                //如果t和原本nums[i-1]位置上的数字相同,说明重复
                ans.add(t);
                nums[i]*=-1;
            }else{
                //如果t和原本nums[i-1]位置上的数字不相同
                //  将此位置上的t与nums[t-1]上的数字进行交换
                //nums[t-1]原本的数放在i的位置上,再将i-1等待下一轮循环再进行比较
                int tmp = nums[t-1];
                nums[t-1] = t;
                nums[i--] = tmp;
            }
        }
        return ans;
    }
leecode_41
public class leecode41 {
    /*给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

    请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

     */
    public int firstMissingPositive(int[] nums) {
        /**
         * 思想:
         *   原地哈希所有元素应该在其应该在的位置上,即1应该在nums[0]的位置
         */
        int len = nums.length;
        for (int i = 0; i < len; i++) {
            //if(nums[i]<0||nums[i]>len||nums[i] - 1== i) continue;

            while(nums[i]>0 && nums[i]<=len && nums[nums[i]-1] != nums[i]){
                int tmp = nums[nums[i]-1];
                nums[nums[i]-1] = nums[i];
                nums[i] = tmp;
            }
        }
        for (int i = 0; i < len; i++) {
            if(nums[i]!=i+1){
                return i+1;
            }
        }

        return  len+1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值