day19_LC学习计划:数据结构基础

觉得之前的版面太过繁琐,虽然没人看,不过还是决定更新一下版面~

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 * 105
-231 <= nums[i] <= 231 - 1
 

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/increasing-triplet-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 觉得可以仿照435.无重叠区间使用动态规划进行解题,超时。

bool increasingTriplet(int* nums, int numsSize){
    int f[numsSize];
    for(int i=0;i<numsSize;i++){
        f[i]=1;
    }
    for(int i=1;i<numsSize;i++){
        for(int j=0;j<i;j++){
            if(nums[i]>nums[j]){
                f[i]=fmax(f[i],f[j]+1);
            }
        }
        if(f[i]==3){
            return true;
        }
    }
    return false;
}

用找到左侧的最小值,右侧的最大值的方法得到,两次遍历得到。



bool increasingTriplet(int* nums, int numsSize){
    if(numsSize<3) return false;
    int leftMin[numsSize],rightMax[numsSize];
    leftMin[0]=nums[0];
    for(int i=1;i<numsSize;i++){
        leftMin[i]=fmin(nums[i],leftMin[i-1]);
    }
    rightMax[numsSize-1]=nums[numsSize-1];
    for(int i=numsSize-2;i>=0;i--){
        rightMax[i]=fmax(nums[i],rightMax[i+1]);
    }
    for(int i=1;i<numsSize-1;i++){
        if(nums[i]>leftMin[i-1]&&nums[i]<rightMax[i+1]){
            return true;
        }
    }
    return false;
}

 还是不太理解为什么可以这样贪心,这次就先记住希望下次就可以做出来了。



bool increasingTriplet(int* nums, int numsSize){
    if(numsSize<3) return false;
    int first=nums[0],second=INT_MAX;
    for(int i=1;i<numsSize;i++){
        int num=nums[i];
        if(num>second){
            return true;
        }else if(num>first){
            second=num;
        }else{
            first=num;
        }
    }
    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 <= 105
-30 <= nums[i] <= 30
保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内
 

进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/product-of-array-except-self
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

首先记得循环两遍是O(2n)=O(n),而不是O(n^2)! 

这道题对于需要利用数组中某个元素左右两边的时候,也使用了左右两侧的数组来保存某个索引两侧来保存左右两侧所需要的结果,上一题是最大最小值,这一题是左右两侧的乘积,类似的方法可以学习一下。

做题时还要记得LC中C里的指针不等于数组。。需要返回的是指针就还得是指针,避免有摸不着头脑的错误。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* productExceptSelf(int* nums, int numsSize, int* returnSize){
    *returnSize=numsSize;
    int leftM[numsSize],rightM[numsSize];
    int* ret=malloc(sizeof(int)*numsSize);
    leftM[0]=1;
    for(int i=1;i<numsSize;i++){
        leftM[i]=leftM[i-1]*nums[i-1];
    }
    rightM[numsSize-1]=1;
    for(int i=numsSize-2;i>=0;i--){
        rightM[i]=rightM[i+1]*nums[i+1];
    }
    for(int i=0;i<numsSize;i++){
        ret[i]=leftM[i]*rightM[i];
    }
    return ret;
}

O(1)的做法:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* productExceptSelf(int* nums, int numsSize, int* returnSize){
    *returnSize=numsSize;
    int* ret=malloc(sizeof(int)*numsSize);
    ret[0]=1;
    for(int i=1;i<numsSize;i++){
        ret[i]=ret[i-1]*nums[i-1];
    }
    int R=1;
    for(int i=numsSize-1;i>=0;i--){
        ret[i]=ret[i]*R;
        R*=nums[i];
    }
    return ret;
}

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 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

枚举即是没出现一个新的数就把它和之前已经出现过的数看看能不能组成一个新的子序列的和等于k。C语言超时。

int subarraySum(int* nums, int numsSize, int k){
    int count=0;
    for(int start=0;start<numsSize;start++){
        int sum=0;
        for(int end=start;end>=0;end--){
            sum+=nums[end];
            if(sum==k){
                count++;
            }
        }
    }
    return count;
}

用哈希表来记录所需要的以nums[i]结尾的前缀和出现的次数,从而可以查询哈希表以O(1)。

第一次见这种用哈希表保存前缀和的方法,还需要多理解,比如这次为什么只使用一个pre变量而不是用pre数组,因为pre[i]的数值只和pre[i-1]相关,则只需要加上之前的pre就可以了,用不上数组。用到的一种方法——用到i的数之和  - 到j的数之和来得到[j...i]之间的数组的和的做法值得记住。

typedef struct {
    int key;
    int val;
    UT_hash_handle hh;
}hashTable;

int subarraySum(int* nums, int numsSize, int k){
    int pre=0,count=0;
    hashTable* map=NULL;
    hashTable* tmp=malloc(sizeof(hashTable));
    tmp->key=0;
    tmp->val=1;
    HASH_ADD_INT(map,key,tmp);
    for(int i=0;i<numsSize;i++){
        pre+=nums[i];
        int newK=pre-k;
        HASH_FIND_INT(map,&newK,tmp);
        if(tmp){
            count+=tmp->val;
        }
        HASH_FIND_INT(map,&pre,tmp);
        if(!tmp){
            tmp=malloc(sizeof(hashTable));
            tmp->key=pre;
            tmp->val=1;
            HASH_ADD_INT(map,key,tmp);
        }else{
            tmp->val++;
        }
    }
    return count;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值