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;
}
}