链表
//迭代反转链表
public static Node iterate(Node head){
Node prev=null,next; //暂存数据
Node curr = head; //当前节点
while (curr != null){
next =curr.next; //保存下一节点,以防后续丢失
curr.next= prev; //将下一节点指向反转上一节点
prev = curr; //保存当前节点,为下次循环充当上一节点数据
curr=next; //进入下一节点处理
}
return prev; //当前节点为null时,上一节点即是反转后的头结点
}
//递归反转链表
public static Node recursion(Node head){
if (head == null || head.next == null){
return head; //如果下一节点为空,结束递归
}
Node new_head = recursion(head.next); //递归先解决最后的反转
head.next.next = head; //将下一节点的指向更改为当前节点
head.next = null; //断开当前节点和下一节点,防止循环
return new_head;
}
//判断链表是否有环
public static boolean hasCycle(Node head){
Set<Node> set = new HashSet<Node>(); //无序不重复,重复返回false
while(head!=null){ //遍历链表直到最后
if (!set.add(head)){ //将链表挨个存入set中
return true; //存不进说明有环
}
head = head.next; //对下一节点进行判断
}
return false;
}
//双指针,省空间复杂度
public static boolean hasCycle2(Node head){
if (head == null || head.next == null){
return false; //若链表为空或只有一个节点不可能有环
}
Node slow = head; //一次只行动一格
Node fast = head.next; //一次只行动两格
while (slow != fast){ //若成环快慢指针一定会相等
if (fast.next == null || fast == null){
return false; //快指针的下一节点为空表面不成环
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
素数个数
//暴力算法判断素数个数
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 x){
for (int i=2; i*i < x; i++){ //乘法过半后重复判断了
if (x % i ==0){ //取余,如为0表明可以被整除,非素数
return false;
}
}
return true;
}
//埃氏筛法,是一种用于查找一定范围内所有素数的高效算法
public static int eratothsthenes(int n){
//创建一个布尔数组:创建一个大小为N+1的布尔数组,
boolean[] isPrime = new boolean[n];
//并将所有索引处的值初始化为false(表示假设它们都是素数)。
Arrays.fill(isPrime, false);
int count = 0;
for (int i=2;i<n;i++){
if (!isPrime[i]){ //如果在布尔数组中为false,执行下列代码
count++;
//将素数的倍数(且小于n)在布尔数组中修改为true(非素数)
for (int j=i*i;j<n;j+=i){
isPrime[j] = true; //如2的倍数都修改为非素数,后续不再判断
} //j+=i相当于j=(i+1)*i
}
}
return count;
}
硬币排序
//硬币排序
//迭代
public static int arrangeCoins(int n){
for (int i=1;i<=n;i++){
n=n-i; //减去前面层数需要的硬币
if (n<=i){
return i;
}
}
return 0;
}
//二分查找
public static int arrangeCoins2(int n){
int low = 0,high=n,mid = 0;
while (low < high){
mid = (low+high)/2; //取中间数
int count = ((1+mid)*mid) /2; //计算前面消耗的数量
if (count == n){
return mid;
}else if (count<n){
low = mid+1; //数量不够,在中间点右边;必须+1,否则有死循环风险
}else{
high = mid; //数量超出,在中间点左边
}
}
return mid+1;
}
合并两个有序数组
//直接合并后排序
public static int[] merge(int[] nums1,int m,int[] nums2,int n){
for (int i=0; i<n; i++){
nums1[m+i] = nums2[i];
}
Arrays.sort(nums1); //数组排序
return nums1;
}
//正向双指针
public static int[] merge2(int[] nums1,int m,int[] nums2,int n){
int p1=0,p2=0;
int[] sorted = new int[m+n]; //中间数组,存排序好的数据
while (p1 < m || p2 <n){
if (p1 == m){ //当nums1先排序完后
sorted[p1 + p2] = nums2[p2++];
}else if (p2 == n){ //当nums2先排序完后
sorted[p1 + p2] = nums1[p1++];
}else{
sorted[p1 + p2] = nums1[p1] < nums2[p2] ? nums1[p1++] : nums2[p2++];
}
}
for (int i = 0; i<m+n; i++){ //循环复制中间数组数据到nums1
nums1[i] = sorted[i];
}
return nums1;
}
//逆向双指针
public static int[] merge3(int[] nums1,int m,int[] nums2,int n){
int p1 = m-1,p2 = n-1;
int p = m+n-1; //获取合并数组大小
while (p1 >=0 || p2 >= 0){
if (p1 == -1){ //当nums1全部提前选取完
nums1[p--] = nums2[p2--];
} else if (p2 == -1){ //当nums2全部提前选取完
nums1[p--] = nums1[p1--];
} else { //判断nums1 2中最后的非零数字谁大,将大的赋值给nums1最后一个0
nums1[p--] = nums1[p1] < nums2[p2] ? nums2[p2--] : nums1[p1--];
}
}
return nums1;
}