每日5道算法题

140 阅读2分钟

1. 数组中随机的重复数字

1.1 问题描述

  在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例
输入
[2, 3, 1, 0, 2, 5, 3]
输出: 2 或 3

1.2 解题思路

  • 可以利用Set集合数据不重复的特性,遍历数组中所有元素,并将元素放入到Set集合中,当Set失败时,说明重复了,将这个元素返回即可。
  • 充分利用好条件,长度为n的数组,数组中元素只能在0-n之间,那么可以根据元素中的数值,数值和下标Index一致就可以了,只要在要移动到的下标元素和要移动元素相同,说明就是有重复的元素,返回即可。

1.3 代码示例

1.3.1 Set方案

public int findRepeatNumber(int[] nums) {
    if(nums.length <= 1) {
        // 只有一个元素或是没有元素时直接返回,没有重复的
        return -1;
    }
    // 缓存已经添加过的数字
    Set<Integer> numCache = new HashSet<>();
    for (int i = 0; i < nums.length; i++) {
        if(!numCache.add(nums[i])) {
            return nums[i];
        }
    }
    return -1;
}

1.3.2 原地更新法

public int findRepeatNumber(int[] nums) {
    if(nums.length <= 1) {
        return -1;
    }
    for (int i = 0; i < nums.length; i++) {
        // 当前下标的元素和下标不一致时进行元素移动
        while(nums[i] != i) {
            // 要移动的元素和移动到的位置上元素一样时说明重复了
            if(nums[i] == nums[nums[i]]) {
                return nums[i];
            }
            // 元素交换
            int temp = nums[nums[i]];
            nums[nums[i]] = nums[i];
            nums[i] = temp;
        }
    }
    return -1;
}

2. 素数个数

2.1 问题描述

   求2 - n(n > 2的正整数)中有多少个素数。
示例
输入:
10
输出:
4

2.2 解题思路

  • 埃式筛选法:通过已经过滤出来的素数去过滤掉其他的数字。

2.3 代码示例

public int eratosthenes(int n) {
    // 定义n个boolean的数组,默认所有的数字都是素数
    boolean[] isPrime = new boolean[n];
    // 素数的个数
    int count = 0;
    
    // 从2开始,因为0和1都是非素数
    for (int i = 2; i < n; i++) {
        if(!isPrime[i]) {
            count++;
            for (int j = i * i; j < n; j+=i) {
                // 因为到这个for循环了,那么i就是素数了,i * i就是合数,
                // 因为有了其他的数可以由两个数相乘得到
                isPrime[j] = true;
            }
        }
    }
    // 返回素数个数
    return count;
}

3. 寻找数组的中心下标

3.1 问题描述

   中心下标左边数据之和等于右边数据之和。存在则返回,存在多个则返回最左边的中心下标,不存在则返回-1
示例 输入
[3,2,3] 输出
1

3.2 解题思路

  • 双指针法:左边数组之和 + 中心下标元素 = 右边数组之和 + 中心下标元素

3.3 代码示例

public int pivotIndex(int[] nums) {
    // 开始时右边数据 = 数组元素之和
    int rightSum = Arrays.stream(nums).sum();
    // 开始时左边数据 = 0;
    int leftSum = 0;
    
    for (int i = 0; i < nums.length; i++) {
        // 从0下标开始累加
        leftSum += nums[i];
        if (leftSum == rightSum) {
            // 说明i已经是中心下标了
            return i;
        }
        // 减去i包含i之前的元素之和
        sum -= nums[i];
    }
}