- 统计素数的个数: ```java
public class 素数个数统计 { /**
* 统计n以内的素数的个数
* 素数: 只能被 1 和自身整除的自然数,0 1 除外
* 例如:输入 100 输出 25
* 重点考察: 埃筛法
*/
/**
* 先用暴力循环
*/
public static int bf(int n) {
int count = 0;
for (int i = 2; i < n; i++) {
count += isPrime(i) ? 1 : 0;
}
return count;
}
/**
* 判断这个数是不是素数
*/
private static boolean isPrime(int k) {
// 小于根号k 就可以了
for (int i = 2; i * i <= k; i++) {
if (k % i == 0) {
return false;
}
}
return true;
}
/**
* 埃筛法
*/
public static int eratosthenes(int n) {
// 初始化的时候全部是false
boolean[] isPrime = new boolean[n];
int count = 0;
for (int i = 2; i < n; i++) {
// 判断如果是素数的话
if (!isPrime[i]) {
count++;
// i 是合数,那么 i*2 一定是合数, i * 3 一定是合数, (ps : j+=i 目的就是为了产生3i,4i...)
// for (int j = 2 i; j < n; j += i) { for (int j = i i; j < n; j += i) { isPrime[j] = true; } } } return count; }
public static void main(String[] args) {
int k = 10000;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
int bf = bf(k);
System.out.println(bf);
stopWatch.stop();
System.out.println(stopWatch.getTime());
stopWatch.reset();
stopWatch.start();
int eratosthenes = eratosthenes(k);
System.out.println(eratosthenes);
stopWatch.stop();
System.out.println(stopWatch.getTime());
}
}
链表反转的问题
```java
package com.study.牛客.算法;
public class 指定区域反转链表 {
/**
* 描述
* 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。
* 例如:
* 给出的链表为 1\to 2 \to 3 \to 4 \to 5 \to NULL1→2→3→4→5→NULL, m=2,n=4m=2,n=4,
* 返回 1\to 4\to 3\to 2\to 5\to NULL1→4→3→2→5→NULL.
* <p>
* 数据范围: 链表长度 0 < size \le 10000<size≤1000,0 < m \le n \le size0<m≤n≤size,链表中每个节点的值满足 |val| \le 1000∣val∣≤1000
* 要求:时间复杂度 O(n)O(n) ,空间复杂度 O(n)O(n)
* 进阶:时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)
*/
public static void main(String[] args) {
ListNode l1 = new ListNode(1);
ListNode l2 = new ListNode(2);
ListNode l3 = new ListNode(3);
ListNode l4 = new ListNode(4);
ListNode l5 = new ListNode(5);
l1.next = l2;
l2.next = l3;
l3.next = l4;
l4.next = l5;
Solution2 solution = new Solution2();
ListNode listNode = solution.reverseBetween(l1, 2, 4);
System.out.println(listNode);
}
}
class Solution2 {
/**
* 解法一:双指针(两次遍历)
* 思路步骤:
* 要反转局部链表,可以将该局部部分当作完整链表进行反转
* <p>
* 再将已经反转好的局部链表与其他节点建立连接,重构链表
* <p>
* 建议使用虚拟头节点的技巧,可以避免对头节点复杂的分类考虑,简化操作。
* <p>
* 反转前后图示:
*/
public ListNode reverseBetween(ListNode head, int m, int n) {
//设置虚拟头节点
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
// 首先要取到 m n 之间的链表
ListNode left = dummyNode;
for (int i = 0; i < m - 1; i++) {
left = left.next;
}
ListNode right = left;
for (int i = 0; i < n - m + 1; i++) {
right = right.next;
}
// 截取出一个子链表
ListNode leftNode = left.next;
ListNode cur = right.next;
// 切断链接
left.next = null;
right.next = null;
// 反转子链表
reserveListNode(leftNode);
// 拼接
left.next = right;
leftNode.next = cur;
return dummyNode.next;
}
private void reserveListNode(ListNode sub) {
ListNode pre = null;
while (sub != null) {
ListNode next = sub.next;
sub.next = pre;
pre = sub;
sub = next;
}
}
}