leetCode - - - 数组(数组中的子数组问题)

目录

1.最大子数组和( LeetCode 53 )

2.和为 K 的子数组(LeetCode 560)

3.寻找数组的中心下标(LeetCode 724)

4.长度最小的子数组(LeetCode 209)

5.总结


1.最大子数组和( LeetCode 53 )

https://leetcode.cn/problems/maximum-subarray/description/

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组

是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

class Solution {
    public int maxSubArray(int[] nums) {
    if(nums.length == 0) return 0;
       int n=nums.length;
       int[] dp=new int[n];
       dp[0]=nums[0];
       int maxSum=dp[0];
       for(int i=1;i<n;i++){
          if(dp[i-1]<0){
            dp[i]=nums[i];
          }else{
            dp[i]=dp[i-1]+nums[i];
          }
          maxSum=Math.max(maxSum,dp[i]);
       }
       return maxSum;
    }
}

2.和为 K 的子数组(LeetCode 560)

https://leetcode.cn/problems/subarray-sum-equals-k/

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 

子数组是数组中元素的连续非空序列。

示例 1:

输入:nums = [1,1,1], k = 2
输出:2

示例 2:

输入:nums = [1,2,3], k = 3
输出:2

解法一:

class Solution {
    public int subarraySum(int[] nums, int k) {
      int count=0;
      int n=nums.length;
      int[]pre=new int[n+1];
      pre[0]=0;
      for(int i=0;i<n;i++){
        pre[i+1]=pre[i]+nums[i];
      }
      
      for(int i=0;i<n;i++){
        for(int j=i;j<n;j++){
            if(pre[j+1]-pre[i]==k){
                count++;
            }
        }
      }
      return count;
}
}

在计算过程中,有两个 for 循环发生了嵌套,时间复杂度来到了 O(n^2) 级别。需要优化。

事实上,我们不需要去计算出具体是哪两项的前缀和之差等于k,只需要知道等于 k 的前缀和之差出现的次数 count,所以我们可以在遍历数组过程中,先去计算以 nums[i] 结尾的前缀和 pre,然后再去判断之前有没有存储 pre - k 这种前缀和,如果有,那么 pre - k 到 pre 这中间的元素和就是 k 了。

解法二:

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer,Integer> map=new HashMap<>();
         // 统计和为 K 的子数组的数量
        int count=0;
        int n=nums.length;
         // 记录遍历到索引为 i 的这个元素时,前缀和的值是多少
        int pre=0;

        //第一个前缀和为k的情况
        // 如数组 [1, 2, 3, 6]
        // 这个数组的累加和数组为 [1, 3, 【6】, 12] 
        map.put(0,1);

        for(int i=0;i<n;i++){
            pre+=nums[i];

            if(map.containsKey(pre-k)){
                count+=map.get(pre-k);
            }

            map.put(pre,map.getOrDefault(pre,0)+1);
        }
        return count;
    }
}

3.寻找数组的中心下标(LeetCode 724)

https://leetcode.cn/problems/find-pivot-index/description/

给你一个整数数组 nums ,请计算数组的 中心下标 

数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。

如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。

示例 1:

输入:nums = [1, 7, 3, 6, 5, 6]
输出:3
解释:
中心下标是 3 。
左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。

示例 2:

输入:nums = [1, 2, 3]
输出:-1
解释:
数组中不存在满足此条件的中心下标。

示例 3:

输入:nums = [2, 1, -1]
输出:0
解释:
中心下标是 0 。
左侧数之和 sum = 0 ,(下标 0 左侧不存在元素),
右侧数之和 sum = nums[1] + nums[2] = 1 + -1 = 0 。

class Solution {
    public int pivotIndex(int[] nums) {
        int sum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        int leftSum=0;
        int rightSum=sum;
        for(int i=0;i<nums.length;i++){
            rightSum=sum-leftSum-nums[i];
            if(leftSum==rightSum){
                return i;
            }else{
                leftSum+=nums[i];
            }
        }
    return -1;
    }
}

4.长度最小的子数组(LeetCode 209)

https://leetcode.cn/problems/minimum-size-subarray-sum/description/

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

找出该数组中满足其总和大于等于 target 的长度最小的 

子数组

 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int minLong=nums.length+1;
        int start=0;
        int end=0;
        int sum=0;
        for(end=0;end<nums.length;end++){
            sum+=nums[end];
            while(sum>=target){
                minLong=Math.min(minLong,end-start+1);
                sum-=nums[start];
                start++;
            }
        }
        return minLong==nums.length+1 ? 0:minLong;
    }
}

5.总结

滑动窗口: 适用于找最小长度的子数组等问题,通过维护一个动态窗口来解决。

前缀和: 用于和相关的问题,通过记录前缀和来高效查询子数组的和。

动态规划: 适用于找最大子数组和等问题,通过状态转移来记录子问题的解。

1. 最大子数组和
题目描述: 给定一个整数数组 nums,找出具有最大和的连续子数组,并返回其和。
解题技巧:
动态规划: 使用 dp 数组来存储以当前位置结尾的子数组的最大和。用 dp[i] 表示以 i 为结尾的最大子数组和。状态转移方程为 dp[i] = max(nums[i], dp[i-1] + nums[i])。

2. 和为 K 的子数组
题目描述: 给定一个整数数组 nums 和一个整数 k,找出 nums 中和为 k 的连续子数组的个数。
解题技巧:
前缀和与哈希表: 使用一个哈希表来记录前缀和的出现次数。通过维护一个累加和pre,每次遍历更新pre 并检查 pre - k 是否存在于哈希表中,从而找到和为 k 的子数组。

3. 寻找数组的中心下标
题目描述: 给定一个整数数组 nums,找出数组的一个中心下标,使得该下标左边所有元素的和等于右边所有元素的和。如果存在多个中心下标,返回最左边的一个。若不存在,返回 -1。
解题技巧:
前缀和: 使用一个变量 Sum 来存储数组的总和。遍历数组时,维护一个 leftSum 来记录当前元素左边的和。可以通过公式 rightSum = Sum - leftSum - nums[i] 来计算右边的和。

4. 长度最小的子数组
题目描述: 给定一个整数 target 和一个正整数数组 nums,找出满足和大于或等于 target 的最小长度子数组。如果不存在,返回 0。
解题技巧:
滑动窗口: 使用两个指针 start 和 end,并维护当前窗口的和。当窗口和大于或等于目标值时,尝试缩小窗口以寻找最小长度。
 

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Roylelele

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值