力扣做题记录——334.递增的三元子序列&238.除自身以外数组的乘积&560.和为K的子数组

这篇博客介绍了如何利用贪心策略和前缀和技巧解决三个经典的数组问题:寻找递增的三元子序列、计算除自身以外的数组乘积以及查找和为K的子数组。每个问题都提供了O(n)时间复杂度和O(1)空间复杂度的解决方案,并给出了详细的思路解析和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

334.递增的三元子序列
给你一个整数数组nums,判断这个数组中是否存在长度为3的递增子序列。
如果存在这样的三元组下标(i, j, k)且满足i < j < k,使得nums[i] < nums[j] < nums[k],返回true;否则,返回false
示例1

输入:nums = [1,2,3,4,5]
输出:true
解释:任何 i < j < k 的三元组都满足题意

示例2

输入:nums = [5,4,3,2,1]
输出:false
解释:不存在满足题意的三元组

示例3

输入:nums = [2,1,5,0,4,6]
输出:true
解释:三元组 (3, 4, 5) 满足题意,因为 nums[3] == 0 < nums[4] == 4 < nums[5] == 6

提示

  • 1 <= nums.length <= 5 * 10^5
  • -2^31 <= nums[i] <= 2^31 - 1

进阶:你能实现时间复杂度为O(n),空间复杂度为O(1)的解决方案吗?

思路
这道题关键就是要贪!题目说要下标和数值都递增对吧,那我之间要求数组中的第一个元素不但是数组中最小的,也要是所有遍历过的最小值,第二个元素也要尽可能地小,只要大于第一个就好了。然后动态维护这两个值,如果nums[i]小于等于第一个元素,那么就更新第一个元素;如果介于第一个和第二个元素之间,就更新第二个元素;如果大于第二个元素,那好事就来了,就可以返回true了。
代码

bool increasingTriplet(vector<int>& nums) {
    int minVal = INT_MAX, maxVal = INT_MAX;
    for (auto num : nums){
        if (num <= minVal){
            minVal = num;
        }
        else if (num <= maxVal){
            maxVal = num;
        }
        else{
            return true;
        }
    }
    return false;
}

238.除自身以外数组的乘积
给你一个整数数组nums,返回数组answer,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据保证数组 nums之中任意元素的全部前缀元素和后缀的乘积都在32 位整数范围内。
不要使用除法,且在O(n)时间复杂度内完成此题。
示例1

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例2

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示

  • 2 <= nums.length <= 10^5
  • -30 <= nums[i] <= 30
  • 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在32 位整数范围内

进阶:你可以在O(1)的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
思路
这道题因为不让用乘法,所以不能先求总乘积再分别除以本身。那么这道题就可以想一下前缀,对于nums[i],它除自身以外数组的乘积为nums[0]逐个乘到nums[i-1]再乘上nums[i+1]逐个乘到nums[n-1]。那么我们可以把左右分开来乘,定义left是nums[i]左侧所有元素的乘积,right是nums[i]右侧所有元素的乘积,一个从左往右迭代,一个从右往左迭代,当遍历完成时,每个位置都已满足题目要求。
代码

vector<int> productExceptSelf(vector<int>& nums) {
    int n = nums.size();
    vector<int> answer(n, 1);
    int left = 1, right = 1;

    for (int i = 0; i < n; i++){
        answer[i] *= left;
        left *= nums[i];
        int m = n - 1 - i;
        answer[m] *= right;
        right *= nums[m]; 
    }
    return answer;
}

560.和为K的子数组
给你一个整数数组nums和一个整数k,请你统计并返回该数组中和为k的子数组的个数 。
示例1

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

示例2

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

提示

  • 1 <= nums.length <= 2 * 10^4
  • -1000 <= nums[i] <= 1000
  • -10^7 <= k <= 10^7

思路
使用前缀和,用一个哈希表 p r e pre pre记录本元素前所有元素的和,如果 p r e − k pre-k prek在这个表中,就说明 p r e [ i ] = p r e [ j ] − k pre[i]=pre[j]-k pre[i]=pre[j]k,即从 i i i j j j之间所有元素的和等于 k k k,计数就+1。
代码

int subarraySum(vector<int>& nums, int k) {
   unordered_map<int, int> mp;
    mp[0] = 1;
    int count = 0, pre = 0;
    for (auto& x:nums) {
        pre += x;
        if (mp.find(pre - k) != mp.end()) {
            count += mp[pre - k];
        }
        mp[pre]++;
    }
    return count;
}

本文题目及部分解答来自力扣:334.递增的三元子序列238.除自身以外数组的乘积560.和为K的子数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值