LeetCode算法入门

文章展示了Java编程中的各种基础算法,包括素数统计(暴力算法和埃拉托斯特尼筛法)、数组操作(双指针、中心下标、平方根计算)、链表反转、数组最大值寻找、两数之和解决方案以及树的深度优先和广度优先搜索
摘要由CSDN通过智能技术生成

素数个数统计

public class Prime {
    int n = 100;

    /*
     * 素数个数统计
     *   素数:只能被1和自身整除的自然数 0,1除外
     *   要求:输入n=100 输出个数:num=25
     *暴力算法
     *
     * */
    public int prime(int num) {
        int count = 0;
        for (int i = 2; i < num; i++) {
            count += isPrime(i) ? 1 : 0;
        }
        return count;
    }

    public boolean isPrime(int x) {
        for (int i = 2; i <= Math.sqrt(x); i++) {
            if (x % i == 0) return false;
        }
        return true;
    }

    @Test
    public void test() {
        int primeNum = prime(100);
        System.out.println(primeNum);
    }
    /*为什么小于等于根号下
    根据n=sqrt(n)*sqrt(n)可得:
    存在和数n,那么存在a*b=n,那么a,b中总有一个数>=sqrt(n),一个数<=sqrt(n)
    所以,只要小于等于sqrt(n)的数不能整除n,n一定为素数

    */

}
public class PrimePlus {
    /*
     * 素数个数统计
     *   素数:只能被1和自身整除的自然数 0,1除外
     *   要求:输入n=100 输出个数:num=25
     *埃筛法
     *
     * */


    @Test
    public void test() {
        System.out.println(eratosthenes(100));
    }

    //埃氏筛选法
    public int eratosthenes(int n) {
        boolean[] isPrime = new boolean[n];//false代表素数,默认
        int count = 0;
        for (int i = 2; i < n; i++) {
            if (!isPrime[i]) {
                count++;
                for (int j = i * i; j < n; j += i) {//j就是和数的标记位
                    isPrime[j] = true;
                }
            }
        }
        return count;
    }

}

双指针算法:删除排序数组中的重复项

public class TwoPointer {
    /*
    * 双指针算法:删除排序数组中的重复项
    *  一个有序数组nums,原地删除重复出现的元素,使每个元素只出现一次,返回删除后的数组新长度
    * */
    int[] nums={0,1,2,2,3,3,4};//返回5

    @Test
    public void test1(){
        System.out.println(removeDuplicates(nums));
    }

    private int removeDuplicates(int[] nums) {
        //如果快指针慢指针不相等,都后移,将j的值给i+1,若相等快指针移动
        if(nums.length==0)return 0;
        int i=0;//慢指针
        for (int j = 1; j < nums.length; j++) {
            if(nums[i]!=nums[j]){
                i++;
                nums[i]=nums[j];
            }
        }
        return i+1;
    }

}

数组“中心下标”

public class CenterMark {
    /*
     * 
     *
     * 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和
     * 如果不存在,返回-1,如果有多个,返回最左边的
     *
     * */
    @Test
    public void test() {
        System.out.println(pointIndex(new int[]{1, 7, 3, 6, 5, 6}));
        System.out.println(pointIndexPlus(new int[]{1, 7, 3, 6, 5, 6}));
    }
    //思路:求出和,一边加一边减
    public int pointIndex(int[] nums) {
        int total = Arrays.stream(nums).sum();//求和的
        int L_sum = 0;
        for (int i = 0; i < nums.length; i++) {
            L_sum += nums[i];
            if (total == L_sum) return i;
            total -= nums[i];
        }
        return -1;
    }

    //若L_sum==R_sum,则2*L_sum+current==sum
    public int pointIndexPlus(int[] nums) {
        int sum = Arrays.stream(nums).sum();
        int L_sum = 0;
        for (int i = 0; i < nums.length; i++) {
            L_sum += nums[i];
            if (2 * L_sum + nums[i + 1] == sum) return i + 1;
        }
        return -1;
    }

}

求x的平方根整数部分:二分法+牛顿迭代

public class Sqrt {
    /*
     * 求x的平方根整数部分
     *
     * */
    @Test
    public void test() {
        System.out.println(SqrtBF(17));
        System.out.println(binarySearch(17));
        System.out.println(newton(17));
    }

    //暴力算法
    public int SqrtBF(int x) {
        int i = -1;
        while (i * i < x) {

            if ((i + 1) * (i + 1) >= x) {
                if ((x - i * i) < ((i + 1) * (i + 1) - x))
                    return i;
                return i + 1;
            }
            i += 1;
        }
        return i;
    }

    //二分法:中间的平方和原值进行比较,小的化将左指针移到中间值下一位,大的化将右指针移到中间值前一位
    public int binarySearch(int x) {
        int index = -1;
        int left = 0;
        int right = x;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (mid * mid <= x) {
                index = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return index;
    }

    //牛顿迭代
    public int newton(int x){
        if(x==0)return 0;
        return (int)sqrt(x/2,x);
    }
    //思想:x的两个因子的平均值更接近于x的根号值
    public double sqrt(double i, int x) {
        double res = (i + x / i) / 2;
        if(res==i){
            return i;
        }else {
            return sqrt(res,x);
        }
    }
}

链表反转

class Node {
    public Node next;
    public Object data;

    public Node(Object data) {
        this.data = data;
    }
}

public class ReverseList {
    //迭代法 思路:用三个变量curr next prev 表示节点当前状态
    public Node iterate(Node head) {
        Node curr = head;
        Node pre = null;
        Node next;
        while (curr != null) {
            next = curr.next;
            curr.next = pre;
            pre = curr;
            curr = next;
        }
        return pre;
    }

    //递归
    public 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;
    }
}

class Test {
    public static void main(String[] args) {
        Node head = new Node(1);
        Node node2 = new Node(2);
        head.next = node2;
        Node node3 = new Node(3);
        node2.next = node3;
        Node node4 = new Node(4);
        node3.next = node4;
        Node node5 = new Node(5);
        node4.next = node5;
        node5.next = null;
        System.out.println(head);
        ReverseList reverseList = new ReverseList();
        //Node iterate = reverseList.iterate(head);
        Node recursion = reverseList.recursion(head);
        //System.out.println(iterate);
        System.out.println(recursion);

    }
}

三个数乘积最大值:线性扫描

public class MaxArray {
    public int getMaxMin(int[] nums) {
        /*
         * 如果数组中有正有负;两个最小的负数和一个最大的正数 或者 三个最大的正数
         * 如果全是正数或负数:最大的三个
         * */
        int min1 = Integer.MAX_VALUE;//最小的数
        int min2 = Integer.MAX_VALUE;//第二小数
        int max1 = Integer.MIN_VALUE;//最大的数
        int max2 = Integer.MIN_VALUE;//第二大数
        int max3 = Integer.MIN_VALUE;//第三小数
        for (int num : nums) {
            if (num < min1) {
                min2 = min1;
                min1 = num;
            } else if (num < min2) {
                min2 = num;
            }
            if (num > max1) {
                max3 = max2;
                max2 = max1;
                max1 = num;
            } else if (num > max2) {
                max3 = max2;
                max2 = num;
            } else if (num > max3) {
                max3 = num;
            }
        }
        return Math.max(min1 * min2 * max1, max1 * max2 * max3);
    }
    @Test
    public void test(){
        System.out.println(getMaxMin(new int[]{-1, -2, 1, 2, 3, 4}));
    }
}

两数之和:MAP+双指针+二分法

public class Solution {
    /*
     * 两数之和
     * */
    //方案一:暴力破解 O(N2)
    public int[] solution(int[] array, int target) {
        for (int i = 0; i < array.length; i++) {
            for (int j = i + 1; j < array.length; j++) {
                if (array[i] + array[j] == target) {
                    return new int[]{i, j};
                }
            }
        }
        return null;
    }

    //方案二:利用map降低时间复杂度 O(N)
    public int[] mapSolution(int[] array, int target) {
        HashMap<Integer, Integer> hashMap = new HashMap<>();
        for (int i = 0; i < array.length; i++) {
            if (hashMap.containsKey(target - array[i])) {
                return new int[]{hashMap.get(target - array[i]), i};
            }
            hashMap.put(array[i], i);
        }
        return null;
    }

    /*
     * 进阶:如果数组是有序的,利用
     *   二分法:O(N log(N))
     *   双指针算法:O(N)
     *
     * */
    //方案三:二分法 假定当前值是一个加数,中间值是另一个加数,改变中间值的位置
    public int[] twoSearch(int[] array, int target) {
        for (int i = 0; i < array.length; i++) {
            int low = 0, high = array.length - 1;
            while (low <= high) {
                int mid = low + (high - low) / 2;
                if (array[mid] == target - array[i]) {
                    return new int[]{i, mid};
                } else if (array[mid] > target - array[i]) {
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            }
        }
        return null;
    }

    //方案四:双指针 左指针和右指针,求和,大的化右指针左移,小的化左指针右移
    public int[] twoPointer(int[] array, int target) {
        int left=0;
        int right=array.length-1;
        while (left<right){
            int isTarget=array[left]+array[right];
            if(isTarget==target){
                return new int[]{left,right};
            }else if(isTarget<target){
                left++;
            }else {
                right++;
            }
        }
        return null;
    }

    @Test
    public void test() {
        System.out.println(Arrays.toString(solution(new int[]{1, 2, 3, 4, 5, 6}, 10)));
        System.out.println(Arrays.toString(mapSolution(new int[]{1, 2, 3, 4, 5, 6}, 10)));
        System.out.println(Arrays.toString(twoSearch(new int[]{1, 2, 3, 4, 5, 6}, 10)));
        System.out.println(Arrays.toString(twoPointer(new int[]{1, 2, 3, 4, 5, 6}, 10)));
    }
}

斐波那契数列第n位的值:递归+双指针

/*
 * 斐波那契数列第n位的值
 *   斐波那契数列:前两位为0,1,后面每一位等于前两位数字之和
 *   第0位开始
 * */
public class Fib {
    //暴力递归 2n次方
    public int calculateBF(int num) {
        if (num == 0) return 0;
        if (num == 1) return 1;
        return calculateBF(num - 1) + calculateBF(num - 2);
    }

    //去重递归 n
    public int calculate(int num){
        int[] arr = new int[num + 1];
        return recurse(arr,num);
    }
    public int recurse(int[] arr, int num) {
        if (num == 0) return 0;
        if (num == 1) return 1;
        if (arr[num] != 0) return arr[num];
        arr[num] = recurse(arr, num - 1) + recurse(arr, num - 2);
        return arr[num];
    }

    //双指针算法
    public int iterate(int num) {
        if (num == 0 || num == 1) return num;
        int low = 0;
        int high = 1;
        for (int i = 1; i < num; i++) {
            int sum = low + high;
            low = high;
            high = sum;
        }
        return high;
    }

    @Test
    public void test() {
        System.out.println(calculateBF(10));
        System.out.println(calculate(10));
        System.out.println(iterate(10));
    }
}

有限数组合并

/*
 * 数组拷贝
 *
 * 两个有序数组,要求拷贝后还是有序数组
 * */
public class MergeSortArray {
    public int[] merge(int[] arr1, int m, int[] arr2, int n) {
        int[] arr1_copy = new int[m];
        for (int i = 0; i < m; i++) {
            arr1_copy[i] = arr1[i];
        }
        //相当于
        System.arraycopy(arr1, 0, arr1_copy, 0, m);

        int p1 = 0;//指向arr(arr1的copy)
        int p2 = 0;//指向arr2
        int p = 0;//指向arr1
        while (p1 < m && p2 < n) {
            //先赋值后++
            arr1[p++] = arr1_copy[p1] < arr2[p2] ? arr1_copy[p1++] : arr2[p2++];
        }
        if (p1 < m) {
            System.arraycopy(arr1_copy, p1, arr1, p1 + p2, m + n - p1 - p2);
        }
        if (p2 < n) {
            System.arraycopy(arr2, p2, arr1, p1 + p2, m + n - p1 - p2);
        }
        return arr1;
    }

    public int[] mergePlus(int[] arr1, int m, int[] arr2, int n) {
        int p1 = m - 1;
        int p2 = n - 1;
        int p = m + n - 1;//arr1的最后一个下标
        while (p >= 0 && p2 >= 0) {
            arr1[p--] = arr1[p1] > arr2[p2] ? arr1[p1--] : arr2[p2--];
        }
        System.arraycopy(arr2, 0, arr1, 0, p2 + 1);
        return arr1;
    }

    @Test
    public void test() {
        int[] arr1 = {1, 3, 5, 7, 9, 0, 0, 0, 0};
        int[] arr2 = {2, 4, 6, 8};
        //System.out.println(Arrays.toString(merge(arr1, 5, arr2, 4)));
        System.out.println(Arrays.toString(mergePlus(arr1, 5, arr2, 4)));
    }
}

深度优先及广度优先

import java.util.LinkedList;
import java.util.Queue;
public class Tree {
    public static void main(String[] args) {
        TreeNode node7 = new TreeNode(7, null, null);
        TreeNode node6 = new TreeNode(6, node7, null);
        TreeNode node5 = new TreeNode(5, null, null);
        TreeNode node4 = new TreeNode(4, null, null);
        TreeNode node3 = new TreeNode(3, node6, null);
        TreeNode node2 = new TreeNode(2, node4, node5);
        TreeNode node1 = new TreeNode(1, node2, node3);
        System.out.println(new Depth().minDepth(node1));
        System.out.println(new Scope().minDepth(node1));
    }
}

//深度优先找最小深度
class Depth {
    public int minDepth(TreeNode root) {
        if (root == null) return 0;
        if (root.left == null && root.right == null) {
            return 1;
        }
        int min = Integer.MAX_VALUE;
        if (root.left != null) {
            min = Math.min(minDepth(root.left), min);
        }
        if (root.right != null) {
            min = Math.min(minDepth(root.right), min);
        }
        return min + 1;
    }
}
//广度优先
class Scope{
   public int minDepth(TreeNode root){
       if (root == null) return 0;
       Queue<TreeNode> queue = new LinkedList();
       root.deep=1;
       queue.offer(root);
       while (!queue.isEmpty()){
           TreeNode node = queue.poll();
           if(node.left==null&&node.right==null){
               return node.deep;
           }
           if(node.left!=null){
               node.left.deep=node.deep+1;
               queue.offer(node.left);
           }
           if(node.right!=null){
               node.right.deep=node.deep+1;
               queue.offer(node.right);
           }
       }
       return 0;
   }
}
//class Queue{
//    Object[] data;
//    int size;
//    public Queue(int length){
//        data=new Object[length];
//    }
//    public void add(Object element){
//        if(size>=data.length)throw new RuntimeException("满了");
//        data[size]=element;
//        size++;
//    }
//    public Object push(){
//        if(size<=0)throw new RuntimeException("没了");
//        Object value = data[0];
//        for (int i = 0; i < size - 1; i++) {
//            data[i]=data[i+1];
//        }
//        data[size-1]=null;
//        size--;
//        return value;
//    }
//}
class TreeNode {
    Object data;
    TreeNode left;
    TreeNode right;
    int deep;
    public TreeNode(Object data, TreeNode left, TreeNode right) {
        this.data = data;
        this.left = left;
        this.right = right;
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为一个程序员,算法数据结构是你必须掌握的基本知识之一。它们是解决问题和优化代码性能的关键工具。 算法是一系列定义良好的步骤,用于解决特定问题或执行特定任务。它们可以是数学公式、逻辑推理或一系列编程指令。算法有助于解决各种问题,例如查找、排序、图形处理等。 数据结构是组织和存储数据的方式。它们可以是简单的变量、数组、链表、栈、队列、树或图等。选择合适的数据结构可以显著提高算法的效率和性能。 入门算法数据结构,你可以从以下几个方面开始学习: 1. 掌握基本的数据结构:了解数组、链表、栈和队列等基本数据结构的概念、特点及其操作。 2. 学习常见的算法:了解常见的排序算法(如冒泡排序、插入排序、快速排序)、查找算法(如线性查找、二分查找)以及递归算法等。 3. 理解复杂度分析:学习如何分析算法的时间复杂度和空间复杂度,了解如何评估算法的效率和性能。 4. 解决实际问题:通过练习和实践,尝试用算法数据结构解决一些实际的编程问题,例如字符串处理、图形处理等。 除了自学,你可以参考一些经典的教材和在线教程来加深理解。一些推荐的资源包括《算法导论》、《数据结构算法分析》、LeetCode等在线平台。 记住,算法数据结构是一个长期学习的过程,不仅需要理解概念,还需要实践和不断地思考如何应用它们解决实际问题。祝你在算法数据结构的学习中取得好成果!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值