算法题 笔记

链表

//迭代反转链表
    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;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值