5.2-5.4:寻找素数、快速横幂运算、二分搜索解决吃香蕉、运货问题

204. 计数质数

  • 什么是质数?(素数)
    一个数如果只能被1和它自身整除,那他就是。
    在这里插入图片描述

1.题目分析

  • 建立辅助函数isPrime(int n),来判断一个数n是否为素数。

    •   public boolean isPrime(int n){
        for (int i = 2; i*i <= n; i++) {
            当有其他的整数因子时
            if (n % i == 0)
                return false;
        }
        return true;
      
      }
  • 注意到,为什么在for循环时,只遍历到sqrt(n)(即,n的平方根)?
    以n=12举例,sqrt(12),是乘积因子的反转临界点,所以到它就够了。

    • 12 = 2 * 6
    • 12 = 3 * 4
    • 12 = sqrt(12) * sqrt(12)
    • 12 = 4 * 3
    • 12 = 6 * 2

2.代码

解法1:循环遍历

时间复杂度:N * logN
空间复杂度:1

   public int countPrimes(int n) {
        int res = 0;
        for (int i = 2; i < n; i++) {
            if (isPrime(i))
                res++;
        }
        return res;
    }

解法2:筛数法

时间复杂度:logN * N

  • 第一层for循环是在找各种因子,
  • 然后在第2层for循环去使用,后边的非素数一定会被第2层找到。
class Solution {
    public int countPrimes(int n) {
        int res = 0;
        boolean[] isPrime = new boolean[n];
        // 填充true
        Arrays.fill(isPrime,true);
        // for (int i = 2; i < n; i++) {
        这么优化是因为,n以内的数,他们的因子在sqrt(n)处发生反转
        for (int i = 2; i*i < n; i++) {  
            如果i是素数,那么所有i的倍数的数 就不是素数
            if (isPrime[i]){
                只要j含有因子i,那么在这里一定会被遍历到
                for (int j = i*2; j < n; j+=i) {
                    isPrime[j] = false;
                }
            }
        }
        for (int i = 2; i < n; i++) {
            if (isPrime[i])
                res++;
        }
        return res;
    }
}

372. 超级次方

在这里插入图片描述
1.题目分析

  • 1.eg:b = [1,5,6,4],那么下图显示的过程,可以往递归的方向考虑

在这里插入图片描述

  • 2.知识点:(a * b) % k = (a % k)(b % k) % k
    在这里插入图片描述

2.代码

class Solution {
    int mod = 1337;
    public int superPow(int a, int[] b) {
        if (b==null || b.length==0)
            return 1;
        LinkedList<Integer> list = new LinkedList<>();
        for (int i = 0; i < b.length; i++) {
            list.add(b[i]);
        }
        return superPowList(a,list);
    }

    public int superPowList(int a, LinkedList<Integer> b){

        if (b.size()==0)
            return 1;
        1.取数组的最后1个元素    
        int last = b.getLast();
        int part1 = mypow(a,last);
        2.删除数组的最后1个元素
        b.removeLast();
        int part2 = mypow(superPowList(a,b),10);
        3.part1 \ part2 都已经取过mod了, 乘积之后还要取模
        return (part1 * part2) % mod;
    }

    计算 a 的 k 次方的函数
    public int mypow(int a, int k){

        a %= mod;
        int res = 1;

        for (int i = 0; i < k; i++) {
            res *= a;
            res %= mod;
        }
        return res;
    }
}

3.高效求幂的方法
在这里插入图片描述

public int pow(int a, int b){
     int mod = 1024; 需要取的模,假设为1024
     if (b==0)
         return 1;
     a %= mod;
     k为奇数时
     if (b%2 == 1){
         return (a * pow(a,b-1)) % mod;
     }
     k为偶数时
     else{
         int part = pow(a,b/2);
         return (part * part) % mod;
     }       
}

875. 爱吃香蕉的珂珂

在这里插入图片描述
1.题目分析

  • 1.主要:吃香蕉的最小速度min=1,最大速度max=数组的最大值;
  • 2.二分搜索 1 ~ max 的区域;
  • 3.假设速度为4,那么在吃一堆数量为10的香蕉时,即使第3小时还剩下2各,那么吃完这2个也不会去吃下一堆。

2.代码

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        左边界  右边界
        int left = 1, right = getMax(piles)+1;
        当left==right时终止while循环
        while (left < right){
            防止溢出
            int mid = left + (right-left) / 2;
            如果能吃完
            if (canFinished(piles,mid,h)){
                右边界左移
                right = mid;
            }
            如果不能吃完
            else {
                left 右移
                left = mid + 1;
            }
        }
        return left;
    }
    H小时内 以speed速度吃完piles[]香蕉 能吃完吗 ?
    public boolean canFinished(int[] piles, int speed, int H){

        int time = 0;
        for (int n: piles) {
            吃完当前堆n个香蕉,所用的时间
            time += timeOf(n,speed);
        }
        return time <= H;
    }
    以speed的速度吃n个香蕉要多久?
    public int timeOf(int n, int speed){
        return (n/speed) + ((n%speed>0) ? 1 : 0);
    }
    获取数组最大值
    public int getMax(int[] piles){
        int res = 0;
        for (int n:piles) {
            res = Math.max(res,n);
        }
        return res;
    }
}

1011. 在 D 天内送达包裹的能力

在这里插入图片描述
在这里插入图片描述
1.题目分析

  • 1.找到运输的最小重量 min = 数组中最重的货物;最大重量:货物总重量;
  • 2.二分搜索
    2.代码
class Solution {
    public int shipWithinDays(int[] weights, int days) {
        
        int left = 0, right = 0;
        for (int n:weights) {
            right += n;
        }
        left = getMax(weights);
        right = right+1;
        
        while (left < right){
            int mid = left + (right-left) / 2;
            if (canTransfer(weights,days,mid)){
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
    
    以速度speed运送 能运完吗?
    public boolean canTransfer(int[] weights, int days, int speed){
        int i = 0;

        for (int j = 0; j < days; j++) {
            int maxCup = speed;
            while ((maxCup-=weights[i]) >= 0){
                i++;
                if (i== weights.length)
                    return true;
            }
        }
        return false;
    }
    public int getMax(int[] piles){
        int res = 0;
        for (int n:piles) {
            res = Math.max(res,n);
        }
        return res;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值