刷题的一天——数据结构(数组)

1、给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

示例:输入:nums = [1,2,3,1] 输出:true

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

代码:大概有两种方法可以完整这个任务,一是可以先排序然后查找是否有重复元素,有则输出true,遍历完毕数组没有重复则输出false;二是通过哈希表完成任务。

(1)排序法:

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
    sort(nums.begin(),nums.end());      //快排
    int n = nums.size();
    for (int i =0;i<=n;i++){
        if(nums[i]==nums[i+1]){
            return true;
        }
    }
    return false;
    }
};

时间复杂度:O(nlogn)。

空间复杂度:O(log N),递归调用栈的深度。

(2)哈希表set查找

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
    unordered_set <int> s;               //创建哈希表
    for(int x:nums){
        if(s.find(x)!= s.end()){           //找相同数值
            return true;
        }
        s.insert(x);                     //元素插入到哈希表中
    }
    return false;
    }
};

哈希表相对时间复杂度更低,只要数组每个元素遍历一遍即可,时间复杂度O(n);空间复杂度相对更大,为O(n)。

(3)哈希表map

和第二个哈希表set大同小异,但是使用哈希表map统计元素数量后再决定。

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
    unordered_map <int,int> s;             //构建哈希表map
    for (int num:nums){                   
        s[num]++;                            //计算元素数量
        if (s[num] >= 2){
            return true;
        } 
    }
    return false;
    }
};

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

示例:

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

这个题是第一次做啊....有点不大会,虽然看题目要求知道要选择动态规划,但是不会实操。于是看了下其他人的题解,学了一下大概要这样做:

(1)动态规划

代码:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    int a = 0, Maxans = nums[0];
    for (const auto&x:nums){
        a = max(a+x,x);                // 连续子数组加和
        Maxans = max(Maxans,a);        //动态规划转移公式,选出最大子数组
    }
    return Maxans;
    }
};

运用动态规划的时间复杂度比较小,遍历即可O(n);空间复杂度O(1)。

(2)分治

除了动态规划以外还可以使用分治的方法,但相对代码没有那么简洁。

class Solution {
public:
   struct status{
       int lsum,rsum,msum,isum;
   };
   status pushup(status l,status r){            //求得最大子数组
       int isum = l.isum + r.isum;              // 整个数组的区间和
       int rsum = max ((r.isum+l.rsum),r.rsum);   //右侧子数组的最大子数组
       int lsum = max ((l.isum+r.lsum),l.lsum);    //左侧子数组的最大子数组
       int msum = max(max(r.msum , l.msum),(r.lsum+l.rsum));   //整个数组的最大子数组,要么等于左边,要么等于右边
                                                               //要么就等于左右连接(左边的右侧最大子数组+右侧的左边最大子数组)
       return status {lsum,rsum,msum,isum};         //返回左侧最大、右侧最大、数组最大、数组总和

   };
   status get(vector<int>&n,int l,int r){
       if (l==r){
        return status{n[l],n[l],n[l],n[l]};        //只有一个就全是这个元素
       }
       int m = (l + r) >>1;
       status lsub = get (n,l,m);
       status rsub = get (n,m+1,r);
       return pushup(lsub,rsub);                     //上面定义的pushup算出四个量
   };


    int maxSubArray(vector<int>& nums) {
    return get(nums, 0, nums.size() - 1).msum;        //嵌套函数算出数组的四个量,但我们只需要msum(数组中的最大子数组),所以就输出了msum

    }
};

比较重点的部分就是pushup函数的设定,是比较经典的分而治之思想的体现。之后的get函数就是进行简单的判定以及找出中间的分隔处了。最后用设定的函数处理数组一步到位。(不得不说pushup函数还是需要比较清晰的思路,而且变量稍稍微微有点多,容易搞错)。最后这种算法的时间复杂度和空间复杂度的计算也相对更加复杂(没有前面的算法那么显而易见)。

时间复杂度:把递归的过程看作是一颗二叉树的先序遍历,那么这颗二叉树的深度的渐进上界为 O(logn),这里的总时间相当于遍历这颗二叉树的所有节点,故总时间的渐进上界是O(n)。
空间复杂度:递归会使用 O(logn) 的栈空间,故渐进空间复杂度为 O(logn)。

 优势:这个题的结构比较简单所以没有体现出这种方法的优势:可以求出所有子区间的最大子数组,这样的话任意部分的最大子数组也会较容易求出。(但的确有点难)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值