数组系列——统计数组中的元素

这篇博客探讨了数组中寻找重复和丢失元素的几种算法,包括使用数学方法、哈希表和位运算。文章给出了LeetCode上的相关题目,并提供了对应的解题思路。

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

645.

集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。

给定一个数组 nums 代表了集合 S 发生错误后的结果。

请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

示例 1:

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

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

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

 思路:想到了最笨的数学方法,即先找出那个重复的数字,再通过数学方法计算本该有的和,再与现在的和进行做差运算,最后就可以得到那个丢失的整数。 

class Solution {
    public int[] findErrorNums(int[] nums) {
            Arrays.sort(nums);
            int sum = nums[0];
            int[] newNums=new int[2];
            for(int a=1;a<=nums.length-1;a++){
                sum+=nums[a];
                if(nums[a]==nums[a-1]){
                    newNums[0]=nums[a];
                }
            }
            int b =nums.length*(1+nums.length)/2;
            newNums[1]= newNums[0]+(b-sum);
            return newNums;
    }
}

其他方法:位运算和哈希表(暂时还没有做,等到学到哈希表再做。)


697.

给定一个非空且只包含非负数的整数数组 nums,数组的度的定义是指数组里任一元素出现频数的最大值。

你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。

示例 1:

输入:[1, 2, 2, 3, 1]
输出:2
解释:
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.
示例 2:

输入:[1,2,2,3,1,4,2]
输出:6

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

思路:

用hash表存储键对,用数组作为value值,含有三个值

【1.第一次出现的地方。2.次数。3.最后出现的地方。】

class Solution {
    public int findShortestSubArray(int[] nums) {
        Map<Integer, int[]> map = new HashMap<Integer, int[]>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            if (map.containsKey(nums[i])) {
                map.get(nums[i])[0]++;
                map.get(nums[i])[2] = i;
            } else {
                map.put(nums[i], new int[]{1, i, i});
            }
        }
        int maxNum = 0, minLen = 0;
        for (Map.Entry<Integer, int[]> entry : map.entrySet()) {
            int[] arr = entry.getValue();
            if (maxNum < arr[0]) {
                maxNum = arr[0];
                minLen = arr[2] - arr[1] + 1;
            } else if (maxNum == arr[0]) {
                if (minLen > arr[2] - arr[1] + 1) {
                    minLen = arr[2] - arr[1] + 1;
                }
            }
        }
        return minLen;
    }
}

448.

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
示例 2:

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

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

思路:

1.创建一个新数组

2.nums【】进行for each循环,每次循环给新数组对应的赋值

3.对新数组进行遍历,没有值的就是缺失的数字

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> list = new ArrayList<>();
        int[] help = new int[nums.length+1];
        for(int num : nums) {
            help[num] = 1;
        }
        for(int i = 1; i < help.length;i++) {
            if (help[i] == 0) {
                list.add(i);
            }
        }
        return list;
    }
}


442.

给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。

找到所有出现两次的元素。

你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗?

示例:

输入:
[4,3,2,7,8,2,3,1]

输出:
[2,3]

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

思路:

 不占用任何额外空间的话,我们需要把数组本身看成是一个哈希表,利用取余的运算方式,做成一个哈希表。

  public List<Integer> findDuplicates(int[] nums) {
        List<Integer> ret = new ArrayList<>();

        int n = nums.length;
        for(int i = 0; i < n; i++){
            nums[(nums[i] - 1) % n] += n;
        }

        for(int i = 0; i < n; i++){
            if(nums[i] > 2 * n) ret.add(i+1);
        }
        return ret;
    }

 

41.

 

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
 

示例 1:

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

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

输入:nums = [7,8,9,11,12]
输出:1

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

思路:

做的第一道困难题,虽然遭遇困难,但也算是通过理解把这道题做出来了。

class Solution {
    public int firstMissingPositive(int[] nums) {
        int len =0;
        int n = nums.length;
         for (int i = 0; i < n; ++i) {
            if (nums[i] <= 0) {
                nums[i] = n + 1;
            }
        }
         for (int i = 0; i < n; ++i) {
            int num = Math.abs(nums[i]);
           if(num<n+1){
                nums[(num - 1) % n] = -Math.abs(nums[(num - 1) % n]);
           }
        }
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) {
                return i+1;
            }
        }
        return n+1;
    }
}

 和442题思路有点像,都是把数组当成是一个哈希表来解答,规避非正数就可以

1.将数组所有的非正数都转化成N+1

2.利用绝对值,为所有存在的数打上一个标记:负数(为什么要用绝对值,因为如果不是绝对值的话,如果出现两个一样的数,就会发生一个数被负数两次而导致负负得正的情况。)

3.如果每一个数都是负数,那么差的最小的正整数就是N+1

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        for(int i=0;i<n;i++){
            while(nums[i]>0&&nums[i]<=n&&nums[nums[i] - 1] != nums[i]){
                int temp=nums[nums[i]-1];
                nums[nums[i]-1]=nums[i];
                nums[i]=temp;
            }
        }
        for(int i=0;i<n;i++){
            if(nums[i]!=i+1) return i+1;
        }
        return n+1;
    }
}

置换法!


274.

给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。

h 指数的定义:h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (n 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。且其余的 n - h 篇论文每篇被引用次数 不超过 h 次。

例如:某人的 h 指数是 20,这表示他已发表的论文中,每篇被引用了至少 20 次的论文总共有 20 篇。

提示:如果 h 有多种可能的值,h 指数 是其中最大的那个。

示例 1:

输入:citations = [3,0,6,1,5]
输出:3 
解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
     由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。
示例 2:

输入:citations = [1,3,1]
输出:1

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

思路:

1.h的值一定是在【1,n】中的一个正整数,因此可以对【1,n】进行二分查找。

2.对每个可能性的值进行判断:即一次for循环的遍历,看是否有足够可能性的值符合。

class Solution {
     public int hIndex(int[] citations) {
        int n=citations.length;
        int l=0,r=n;
        //二分引用次数
        while(l<=r){
            int mid = l + (r-l)/2;
            if(check(citations,mid)){
                l=mid+1;
            }else{
                r=mid-1;
            }
        }
        return r;
    }
    public boolean check(int[] citations, int mid) {
        int count=0;
        for (int citation : citations) {
            //如果论文引用次数 >= 当前引用次数,符合要求的篇数+1
            if(citation>=mid){
                count++;
            }
        }
        //如果符合要求篇数>=引用次数,则当前值可以为H指数
        return count>=mid;
    }

}

 leetcode评论中发现的巧妙的方法:

1.首先排序数组,把数组按顺序排列。

2.默认h为数组的长度,即满的,然后遍历数组。

3.如果数组中该index的元素小于当前h,那么h--。

4.最后返回h。

class Solution {
    public int hIndex(int[] citations) {
        //[3,0,6,1,5] - >[0,1,3,5,6]
        Arrays.sort(citations);
        //默认这5篇被引用了5次
        int h = citations.length;
        for(int i=0;i<citations.length;i++){
            //比较小于则 h-1
            if(citations[i] < h){
                h--;
            }
        }
        return h;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

troubles_killer

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

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

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

打赏作者

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

抵扣说明:

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

余额充值