数组中出现超过一半的数字&&2数之和

这是我的第一篇刷题处女作,写作的目的主要有个:
第一:记录自己所学的知识,加深印象,巩固基础。
第二:分享自己的知识经验,希望能够帮助广大的互联网小伙伴们。

第一次写算法,没有经验,希望小伙伴们能够指出我的错误,让我继续成长。


第一题:给定一个序列,找出其中出现了超过一半的数。

第一题比较简单,可以使用方法也很多,下面介绍三中方法来解决这个问题:

  • 排序
 public int getNumMoreHalf(int[] a){
        //快速排序,这里最好是将快排写出来,非非比较懒,就没有写了。
        Arrays.sort(a);
        //我们将一个数组排序之后,那么a.length/2这个位置必然是出现超过一半的数。
        return a[a.length/2];
 }

时间复杂度:O(nlg2n)

空间复杂度:O(lg2n),主要体现在递归上。

  • HashMap计数
public int getNumMoreHalf(int[] a){
    //key:a[i]  value:a[i]出现的次数
    Map<Integer,Integer> map=new HashMap<>();
    //统计计数
    for(int i=0;i<a.length;i++){
        //这个方法用来计数统计真的很方便呢,如果Map中有a[i],就把原来的值+1,否则就是0+1。
        map.put(a[i],map.getOrDefault(map.get(a[i]),0)+1);
    }
    int num=0;
    //找到结果
    for(Map.Entry<Integer,Integer> m:map.entrySet()){
        if(m.getValue()>a.length/2){
            num=m.getKey();
        }
    }
    return num;
}

时间复杂度:O(n)

空间复杂度:O(n)

  • 摩尔投票(2个不同的数相互抵消,那么最后剩下的一定是那个超过一半的数)
public int getNumMoreHalf(int[] nums ){
    int count=0,target=0;
    for(int i=0;i<nums.length;i++){
        if(count==0) target=nums[i];
        count+=nums[i]==target?1:-1;
    }
    //如果可能不存在超过一半的数,那么我们最后还需要判断这个数字出现的次数知否超过一半,
    //因为摩尔投票算法只能求出超过一半的数,并不能求出数学上说的众数(出现次数最多的数)
    return target;
}

摩尔投票法:

  • 票数和: 由于众数出现的次数超过数组长度的一半;若记 众数 的票数为 +1 ,非众数 的票数为 −1 ,则一定有所有数字的 票数和 > 0
  • 票数正负抵消: 设数组 nums 中的众数为 x ,数组长度为 n 。若 nums 的前 a 个数字的 票数和 = 0 ,则 数组后 (n−a) 个数字的 票数和一定仍 >0 ,即后(n−a) 个数字的 众数仍为 x 。
  • 示意图如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GLhXEFIT-1600182283688)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20200915224736849.png)]

以上说的众数即时出现超过一般的数。

更加详细请参考:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/solution/mian-shi-ti-39-shu-zu-zhong-chu-xian-ci-shu-chao-3/

时间复杂度:O(n)

空间复杂度:O(1)

第二题:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s,找出一组即可。

这一题也是比较简单的,同样介绍四种方法来解决这个问题:

  • 暴力破解
public int[] getTargetNum(int[] a,int target){
    int sum=0;
    for(int i=0;i<a.length;i++){
        for(int j=i+1;j<a.length;j++){
            if((a[i]+a[j])==target){
                return new int[]{a[i],a[j]};
            }
        }
    }
    return new int[]{};
}

这个就不用写注释了吧,相信小伙伴都能看的懂的。

时间复杂度:O(n^2)

空间复杂度:O(1)

  • 二分法
public int[] getTargetNum(int[] a,int target){
    for(int i=0;i<a.length;i++){
        int left=i+1,right=a.length-1,num=target-a[i];
        //在暴力破解的基础上,第二层循环使用二分法
        while(left<=right){
            int middle=left+(right-left)/2;
            if(a[middle]>num){
                right=middle-1;
            }else if(a[middle]<num){
                left=middle+1;
            }else {
                return new int[]{a[i],a[middle]};
            }
        }
    }
    return new int[]{};
}

在暴力破解的基础上,利用数组有序的特性在第二层循环使用了二分法,提高了效率。

时间复杂度:O(nlog2n)

空间复杂度:O(1)

  • HashMap法
public int[] getTargetNum(int[] a,int target){
    Set<Integer> set=new HashSet<>();
    for(int i=0;i<a.length;i++){
        //在将每一个元素a[i]加入到HashMap的时候,我们使用O(1)的时间的复杂度查看target-a[i]是否也在HashMap中。
        if(set.contains(target-a[i])){
            return new int[]{target-a[i],a[i]};
        }
        set.add(a[i]);
    }
    return new int[]{};
}

在将每一个元素a[i]加入到HashMap的时候,我们使用O(1)的时间的复杂度查看target-a[i]是否也在HashMap中。,由于HashSet的底层实现是Hash Map,于是我在这个就将其称呼为HashMap。

时间复杂度:O(n)

空间复杂度:O(n)

  • 双指针
public int[] getTargetNum(int[] a,int target){
    //定义2个指针,一个指向数组的左边,一个指向数组的右边。
    int i=0,j=a.length-1;
    //将2个指针向右向左移动来获得最终的答案。
    while(i<j){
        if(a[i]+a[j]<target){
            i++;
        }else if(a[i]+a[j]>target){
            j--;
        }else{
            return new int[]{a[i],a[j]};
        }
    }
    return new int[]{};
}

示意图如下:

在这里插入图片描述

时间复杂度:O(n)

空间复杂度:O(1)


以上2道题都是比较简单的题,但是都很好的体现了算法技巧与思维,实在是入门必刷的题。

码字不易,请按下你们的大拇指,你们的给力,就是我的动力,我是袁非非!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值