力扣第 326 场周赛

61 阅读3分钟

第一题:统计能整除数字的位数

题目详情

题目代码

public int countDigits(int num) {
    int n = num; // 用来记录数字
    int ans = 0; //最后返回的答案
    int cur = 0; //记录数字每个位置上的数据
    while(n != 0){   //当数字还有位数的时候进行循环
        cur = n % 10;  //将每一位的数据取下来
        if(num % cur == 0){   //判断能不能除尽
            ans++;           //如果能除尽就让答案加1
        }
        n = n / 10;         //最后去除那位上的数据,方便取后一位的数据
    }
    return ans;     //跳出循环,返回答案。
}

第二题:数组乘积中的不同质因数数目

题目详情

题目代码

public int distinctPrimeFactors(int[] nums) {
    HashSet<Integer> set = new HashSet<>();      // 创建一个哈希表用来存储出现过的数字,最后返回哈希表的大小就是答案。
    for(int i = 0;i< nums.length;i++){
        solve(nums[i] , set);                 //遍历数组,将数组里面的每一位都分解成素数的乘积。
    }
    return set.size();
}
//这个函数就是将传过来的数据num分解,看看它是由什么素数相乘的,然后将分解出来的素数放到哈希表里面记录
public void solve(int num , HashSet<Integer> set){
    //这个是判断这个数是不是素数的,如果是素数就直接放到哈希表里面,然后返回
    if(pd(num)){
        set.add(num);
        return;
    }
    //这个就是从最小的2开始分解,如果能除尽,就表示还可以分解。
    for(int i = 2;i<=Math.sqrt(num);i++){
        if(num % i == 0){
            solve(i , set);
            solve(num / i , set);
        }
    }
}
//这个函数就是用来判断是不是素数的。
public boolean pd(int num){
    for(int i = 2;i<=Math.sqrt(num);i++){
        if(num % i == 0){
            return false;
        }
    }
    return true;
}

第三题:将字符串分割成值不超过 K 的子字符串

题目详情

题目代码

public int minimumPartition(String s, int k) {
    return process(s , 0 , k);
}
//这个函数的用处就是用来划分字符串,看看是否合理。
//变量:s 表示的就是字符串
//变量:index 表示的就是现在运行到哪了。
//变量:k 表示的就是不能超过的数字。
public int process(String s , int index , int k){
    //如果运行的最后了,我们就返回0,表示结束
    if(index == s.length()){
        return 0;
    }
    //这个变量表示的就是截取的长度。
    int i = 1;
    //从s字符串里面截取长度之后赋值给num
    String num = s.substring(index , index + i);
    //这个循环就是用来不断的扩大num,让num尽可能的大,当然,我们截取的长度也不能超过字符串的长度。
    while(Long.valueOf(num) <= k && i + index < s.length()){
        //如果还能截取,就让长度变长。
        i++;
        num = s.substring(index , index + i);
    }
    //这个表示的是截取到最后了还是比k小,那我们就返回1,表示可以
    if(i + index == s.length() && Long.valueOf(num) <= k){
        return 1;
    }
    //如果,截取的长度是1,而且没有截取到最后,那么我们就认为这个是截取失败的。
    if(i == 1){
        return -1;
    }else{
        //我们用next变量看看之后截取表现
        int next = process(s , index + i - 1, k);
        //如果next == -1,表示后面的截取失败了,那么我们也返回-1
        if(next == -1){
            return -1;
        }else{
            //如果截取成功了,返回了一定的个数,那么我们就返回next+1.
            return next + 1;
        }
    }
}

代码优化

public int minimumPartition(String s, int k) {
    //用来存储答案的,当然也可以优化到不用数组,用一个变量也可以完成
    int[] dp = new int[s.length() + 1];
    //将第一个变成1,因为如果第一个是的话,那就是1.
    dp[0] = 1;
    //这个变量就是来记录截取字符串的大小是多少
    Long num = 0L;
    //这个循环就是用来截取字符串的,并且判断是否合法
    for(int i = 1;i<dp.length;){
        //这个是截取字符串
        num = num * 10 + (s.charAt(i - 1) - '0');
        //这个是判断是否大于指定数据
        boolean flag = num > k;
        //这个是表示如果截取的是一位,但是还是大于的话,那就不可能截取成功,返回-1.
        if(flag && num / 10 == 0){
            return -1;
        }else if(flag){
            //这个表示的是大于指定数,且不是一位。
            //前一个加加,为的是防止之后一次循环的时候将后面的数据更改。因为此时,我们的i是不变的。如果下一位加上之后还是小于,那么就会导致正确的数被更改。
            dp[i - 1]++;
            //这个就是让后面的数+1.因为大于了,所以,截取的个数是要+1的
            dp[i] = dp[i - 1];
            //置空
            num = 0L;
        }
        //如果乜有大于的话,那就继续往后面走,加数字
        if(!flag){
            dp[i] = dp[i - 1];
            i++;
        }
    }
    //最后返回答案。
    return dp[s.length()];
}

第四题:范围内最接近的两个质数

题目详情

题目代码

//这个表示的是最大值
private final static int NUM = (int) 1e6;
//这个表示的是1到1e6中间有多少个素数
private final static int[] arr = new int[78498];
//这个静态代码块是用来初始化arr,将素数都收集起来的。
static{
    //这个表示的是哪一个是素数,如果不是素数就是true,如果是素数就是false
    boolean[] flag = new boolean[NUM + 1];
    //这个index是素数记录到哪了。
    int index = 0;
    //这个循环是用来遍历全部的数。
    for(int i = 2;i<NUM;i++){
        //如果之前没有数让这个格子变成true,就表示这个格子是素数
        if(!flag[i]){
            //记录素数
            arr[index++] = i;
            //这个就是用来将这个数的倍数变成true,表示,只要是这个数的倍数就不是素数。
            for(int j = i;j<=NUM/i;j++){
                flag[i * j] = true;
            }
        }
    }
}
public int[] closestPrimes(int left, int right){
    //利用二分查找,找到开始的位置
    int begin = find(left);
    //这两个变量记录的是答案
    int ans1 = -1;
    int ans2 = -1;
    //这个循环是从开始的素数,走到最后。
    for(int i = begin;i + 1 < arr.length && arr[i + 1]<=right;i++){
        //如果之前没有被赋值过,或者相邻的素数相减小于原来的答案,就改变。
        if(ans2 < 0 || arr[i + 1] - arr[i] < ans2 - ans1){
            ans1 = arr[i];
            ans2 = arr[i + 1];
        }
    }
    return new int[]{ans1 , ans2};
}
//这个是利用二分查找找到大于等于给定值的素数。
public int find(int num){
    int left = 0;
    int right = arr.length - 1;
    while(left < right){
        int mid = left + (right - left)/2;
        if(arr[mid] > num){
            right = mid;
        }else if(arr[mid] < num){
            left = mid + 1;
        }else{
            return mid;
        }
    }
    return left;
}