Java基础 - 代码练习

第一题:集合的运用(幸存者)

java 复制代码
public class demo1 {
    public static void main(String[] args) {
        ArrayList<Integer> array = new ArrayList<>();  //一百个囚犯存放在array集合中
        Random r = new Random();
        for (int i = 0; i < 100; i++) {
            OUT:
            while (true) {
                int n = r.nextInt(200)+1;  //生成随机数1-200
                //用for循环对比有没有重复比较复杂
//                for (int j = 0; j < i; j++) {
//                    if(n==array.get(j)){  //随机数重复
//                        continue OUT;
//                    }
//                }
                if(array.contains(n)){  //随机数重复
                    continue OUT;
                }
                //说明没有重复的
                array.add(n);
                break OUT;
            }
        }
        System.out.println(array);

        ArrayList<Integer> arr = new ArrayList<>(); //保存一百个囚犯第一次的存放位置
        arr.addAll(array);
        System.out.println(arr);

        //题中要求位置从1开始计数,现在我们的位置是从0开始,所以后续计算要+1
        while(array.size()>1){
            for (int i = array.size()-1; i>=0; i--) {
                if((i+1)%2==1){  //奇数位置
                    array.remove(i);
                }
            }
            System.out.println(array);
        }

        System.out.println("幸存者编号:" + array.get(0));
        System.out.print("幸存者第一次所占的位置(从1开始算):");
        System.out.print(arr.indexOf(array.get(0)) + 1);
    }
}

第二题:基础编程能力

java 复制代码
//User
public class User {
    private Long id; //用户id
    private String name; //用户名
    private String gender; //用户性别
    private LocalDate birthday; //用户生日

    public User() {
    }

    public User(Long id, String name, String gender, LocalDate birthday) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.birthday = birthday;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public LocalDate getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

//demo2
public class demo2 {
    public static void main(String[] args) {
        //创建一个ArrayList集合
        List<User> users = new ArrayList<>();

        //解析字符串
        String userStrs = "10001:张三:男:1990-01-01#10002:李四:女:1989-01-09#10003:王五:男:1999-09-09#10004:刘备:男:1899-01-01#10005:孙悟空:男:1900-01-01#10006:张三:女:1999-01-01#10007:刘备:女:1999-01-01#10008:张三:女:2003-07-01#10009:猪八戒:男:1900-01-01";
        String[] strs = userStrs.split("#"); //用#号把每个用户的数据先拆分开
        //System.out.println(Arrays.toString(strs)); //[10001:张三:男:1990-01-01, 10002:李四:女:1989-01-09, 10003:王五:男:1999-09-09, 10004:刘备:男:1899-01-01, 10005:孙悟空:男:1900-01-01, 10006:张三:女:1999-01-01, 10007:刘备:女:1999-01-01, 10008:张三:女:2003-07-01, 10009:猪八戒:男:1900-01-01]

        for (int i = 0; i < strs.length; i++) {
            String s = strs[i];
            String[] str2 = s.split(":");  //用:号把每个用户的个人数据(id 姓名 性别 生日)拆分开
            //str2[0]代表id  str2[1]代表姓名  str2[2]代表性别  str2[3]代表生日

            long id = Long.parseLong(str2[0]); //把用户id从String型转换成long型
            //long id = Long.valueOf(str2[0]); //把用户id从String型转换成long型

            //把生日转换成从字符串转换成LocalDate
            LocalDate birth = LocalDate.parse(str2[3]);
//            String[] time = str2[3].split("-"); //time[0]代表年 time[1]代表月 time[2]代表日
//            int year = Integer.parseInt(time[0]);
//            int month = Integer.parseInt(time[1]);
//            int day = Integer.parseInt(time[2]);
//            LocalDate birth = LocalDate.of(year,month,day);

            User user = new User(id,str2[1],str2[2],birth);
            users.add(user);
        }

        System.out.println(users);

        System.out.println("============================================");

        //遍历List<User>集合,统计每个名字出现的次数
        Map<String,Integer> map = new HashMap<>();
        for (int i = 0; i < users.size(); i++) {
            User user = users.get(i);
            if(map.containsKey(user.getName())){ //如果用户的名字在map的键中存在
                map.put(user.getName(),map.get(user.getName())+1);
            }else{ //如果用户的名字在map的键中第一次出现
                map.put(user.getName(),1);
            }
        }
        //System.out.println(map);
        map.forEach((k,v) -> System.out.println(k+":"+v+"次"));
    }
}

第三题:JDK8新时间的应用

java 复制代码
public class demo3 {
    public static void main(String[] args) {
        LocalDate ld = LocalDate.of(2022,2,3); //记录首次休息日
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入您查询月份(XXXX-X):");
            String s = sc.next();
            if(!s.matches("\\d{4}-\\d{1,2}")){
                System.out.println("您输入的时间格式不正确,请重新输入");
                continue;
            }else {
                String[] str = s.split("-");
                int year = Integer.parseInt(str[0]); //查询的年份
                int month = Integer.parseInt(str[1]); //查询的月份呢
                if(month > 12 || month < 1){ //查询的月份不是1-12之间
                    System.out.println("请输入正确的月份(1-12)~~~");
                }else if (year < 2022 || (year == 22 && month <= 2)) {  //查询月份不在2022年2月之后
                    System.out.println("请输入2022年2月之后的月份~~~");
                } else { //查询月份在2022年2月之后 且 月份符合规范(1-12)
                    int days = dayNum(year, month); //该月有几天
                    //打印该月的上班情况
                    for (int i = 1; i < days; i++) {
                        LocalDate date = LocalDate.of(year, month, i);
                        //判断该日是否是休息日
                        Long next = date.toEpochDay() - ld.toEpochDay();  //获取相差天数
                        if (next % 3 == 0) {
                            System.out.print(date + "[休息]");
                            //判断休息日是否是周末(周六 周日)
                            if(date.getDayOfWeek() == DayOfWeek.SATURDAY){
                                System.out.print("[周六] ");
                            }else if(date.getDayOfWeek() == DayOfWeek.SUNDAY){
                                System.out.println("[周日] ");
                            }else{
                                System.out.print(" ");
                            }
                        } else if (next % 3 == 1 || next % 3 == 2) {
                            System.out.print(date + " ");
                        }
                    }
                    break;
                }
            }
        }
    }

    public static int dayNum(int year, int month) {
        int num = 0;
        switch (month){
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                num = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                num = 30;
                break;
            case 2:
                if((year%4==0 && year%100!=0) || (year%400==0)){
                    //闰年
                    num = 29;
                }else{
                    num = 28;
                }
                break;
            default:
                System.out.println("月份有误");
                break;
        }
        return num;
    }
}

第四题:手写ArrayList集合

java 复制代码
//MyArrayList
public class MyArrayList<E> {
    private Object[] arr = new Object[10];
    private int count = 0; //记录数组中现存有几个数据
    private double gene = 0.8; //激活因子

    //往集合中添加数据(返回值是boolean类型)
    public boolean add(E e){
        arr[count] = e;
        count++;
        if(count >= arr.length * gene){
            Object[] arr1 = Arrays.copyOf(arr,arr.length * 2); //如果数组中的数据个数等于或超过数组最大范围的80%,则扩容两倍
            arr = arr1;
        }
        //System.out.println(Arrays.toString(arr));
        //但是由于用户只是当成集合,应该设计成看不到最后扩容的null值位
        //比如用户存入第一个数据11,用户希望返回的是[11],不是[11,null,null...]
//        Object[] rs = Arrays.copyOf(arr,count);
//        System.out.println(Arrays.toString(rs));

        return true;
    }

    //根据索引查询指定元素
    public E get(int index) {
        //但是由于用户只是当成集合,应该设计成看不到最后扩容的null值位
        //比如用户存入第一个数据11,用户希望返回的是[11],不是[11,null,null...]
        //因此用户输入超过他自己存入个数的索引值,就产生了越界
        if(index >= count || index < 0){ //索引值越界
            throw new ArrayOutException("您输入的索引越界");
        }else{
            return (E) arr[index];
        }
    }

    //根据索引删除指定元素(返回值是被删除的元素)
    public E remove(int index){
        if(index >= count || index < 0) { //索引值越界
            throw new ArrayOutException("您输入的索引越界");
        }else{
            E e = (E) arr[index]; //记录被删除元素
            //删除的元素是最后一个元素
            if(index == arr.length-1){  //由于扩容机制,所以不会删除的元素永远不会是数组的最后一个
                arr[index] = null;
                return e;
            }
            //删除的元素不是最后一个元素,需要进行移位(后面的数前移)
            for (int i = index + 1; i < arr.length; i++) {
                if(i != arr.length-1){
                    arr[i-1] = arr[i];
                }else{
                    arr[i] = null;   //由于扩容机制,永远都没有存满,最后一位永远是null,因此最后一个数的前移不会导致最后一位多出来一个重复的数
                }
            }
            //System.out.println(Arrays.toString(arr));
            count--; //数组元素个数-1
            //但是由于用户只是当成集合,应该设计成看不到最后扩容的null值位
            //比如用户存入第一个数据11,用户希望返回的是[11],不是[11,null,null...]
//            Object[] rs = Arrays.copyOf(arr,count);
//            System.out.println(Arrays.toString(rs));

            return e;
        }
    }

    //返回集合大小
    public int size(){
        return count;
    }

    //遍历集合
    public void forEach1(){
        for (int i = 0; i < count; i++) {
            System.out.print(arr[i]+ " ");
        }
        System.out.println();
    }

    //遍历集合(可以用Lambda表达式)
    public void forEach(MyConsumer<E> action){
        Objects.requireNonNull(action);
        for (int i = 0; i < count; i++) {
            action.accept((E) arr[i]);
        }
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < count; i++) {
            E e = (E) arr[i];
            sb.append(e).append(i==count-1?"":", "); //判断该元素是否是最后一个数据,是否需要加,
        }
        sb.append("]");
        return sb.toString();
    }
}

//MyConsumer
public interface MyConsumer<E> {
    void accept(E e);
}

//ArrayOutException
public class ArrayOutException extends RuntimeException{
    public ArrayOutException(){

    }
    public ArrayOutException(String message){
        super(message);
    }
}

//demo4
public class demo4 {
    public static void main(String[] args) {
        MyArrayList<Integer> arr = new MyArrayList<>();
        arr.add(11);
        arr.add(22);
        arr.add(33);
        arr.add(44);
        arr.add(55);
        arr.add(66);
        arr.add(77);
        arr.add(88);
        arr.add(99);

        System.out.println(arr); //[11, 22, 33, 44, 55, 66, 77, 88, 99]
        System.out.println(arr.size()); //集合大小 9

        System.out.println(arr.get(8)); //索引8是99
        //System.out.println(arr.get(11)); //您输入的索引越界
        //System.out.println(arr.get(-1)); //您输入的索引越界

        System.out.println(arr.remove(7)); //返回被删除的元素88

        System.out.println(arr.size()); //集合大小 8

        arr.forEach1(); //11 22 33 44 55 66 77 99

        arr.forEach((Integer integer) -> System.out.print(integer + " ")); //11 22 33 44 55 66 77 99
    }
}

第五题:二分查找的应用

java 复制代码
public class demo5 {
    public static void main(String[] args) {
        int[] nums = {};
        int target = 0;
        int[] rs = isExist(nums,target);
        System.out.println(Arrays.toString(rs));
    }

    //查找目标值对应的最左边的位置
    public static int getLeftIndex(int[] nums, int target){
        int rs = -1; //数据不存在为-1
        //二分查找
        int left = 0;
        int right = nums.length-1;
        while (left<=right){
            int middle = (left + right) / 2;
            if(nums[middle]==target){
                rs = middle; //先临时存放第一次找到目标值的位置
                //二分查找该元素的 左边 是否还存在目标值
                right = middle - 1;
            }else if(nums[middle] < target){
                left = middle + 1;
            }else if(nums[middle] > target){
                right = middle - 1;
            }
        }
        return rs;
    }

    //查找目标值对应的最右边的位置
    public static int getRightIndex(int[] nums, int target){
        int rs = -1; //数据不存在为-1
        //二分查找
        int left = 0;
        int right = nums.length-1;
        while (left<=right){
            int middle = (left + right) / 2;
            if(nums[middle]==target){
                rs = middle; //先临时存放第一次找到目标值的位置
                //二分查找该元素的 右边 是否还存在目标值
                left = middle + 1;
            }else if(nums[middle] < target){
                left = middle + 1;
            }else if(nums[middle] > target){
                right = middle - 1;
            }
        }
        return rs;
    }

    //复杂度O(log2n)
    public static int[] isExist(int[] nums, int target) {
        int[] rs = {-1,-1}; //记录返回值
        if(nums == null ||nums.length == 0){ //如果 数组不存在 或 数组为空
            return rs;
        }
        //数组不为空
        rs[0] = getLeftIndex(nums,target);
        rs[1] = getRightIndex(nums,target);
        return rs;
    }

    //复杂度O(n)
    public static int[] isExist1(int[] nums, int target) {
        int[] rs = new int[2];
        int count = 0; //记录第几次找到该数字
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] == target && count == 0){ //第一次找到该数字
                rs[0] = i;
                count++;
            }else if(nums[i] == target && count != 0){ //不是第一次找到该数字
                rs[1] = i;
                count++;
            }
        }
        if(count == 0){ //说明未找到
            rs[0] = -1;
            rs[1] = -1;
        }
        return rs;
    }
}

第六题:手写链表、反转链表

java 复制代码
//MyLinkedList
public class MyLinkedList<E> {
    private int size;
    /**
     * 定义了一个私有的内部类,作为链表的结点
     */
    public static class Node<E>{
        E data;
        Node<E> next;

        public Node(E data, Node<E> next) {
            this.data = data;
            this.next = next;
        }
    }

    public Node<E> add(){
        Node<E> head = null;
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请您输入当前结点的数据值(exit为结束):");
            String data = sc.next();
            if(data.equals("exit")){ //如果输入的是exit则结束
                break;
            }
            //输入不是exit
            if(head==null){ //第一次创建结点
                head = new Node(data,null);
                size++;
            }else{
                //已存在头结点,往后插入结点(尾插法)
                Node<E> temp = head;
                //让temp走到尾部
                while(temp.next != null){
                    temp = temp.next;
                }
                //把当前结点值创建出来,加入尾部
                temp.next = new Node(data,null);
                size++;
            }
        }
        return head; //返回链表是返回链表的头结点
    }

    public Node<E> reverse(Node<E> head,int left,int right){
        if(head == null || left < 1 || left > size || right < 1 || right > size || left >= right){
            return head;
        }
        //反转
        //先找到左结点的位置
        //从左结点遍历到右结点,然后把数据存到集合中
        Node<E> first = head; //遍历结点标识
        Node<E> mark = null; //记录左结点
        List<E> data = new ArrayList<>();
        int index = 0;
        while(first != null){
            index++;
            if(index == left){
                mark = first;
            }
            if(index>=left && index<=right){
                data.add(first.data);
            }
            if(index == right){
                break;
            }
            first = first.next;
        }
        
        //倒序遍历集合
        for (int i = data.size()-1; i >= 0; i--) {
            E e = data.get(i);
            mark.data = e;
            mark = mark.next;
        }
        
        return head;
    }

    public void forEach(Node<E> head){
        if(head == null){
            System.out.println(head);
            return;
        }

        while(head != null){
            System.out.print(head.data+" ");
            head = head.next;
        }
        System.out.println();
    }

}

//demo6
public class demo6 {
    public static void main(String[] args) {
        MyLinkedList<String> list = new MyLinkedList<>();
        MyLinkedList.Node<String> head = list.add();
        list.forEach(head);
        MyLinkedList.Node<String> head2 = list.reverse(head,2,5);
        list.forEach(head2);
    }
}
相关推荐
刃神太酷啦9 分钟前
力扣校招算法通关:双指针技巧全场景拆解 —— 从数组操作到环检测的高效解题范式
java·c语言·数据结构·c++·算法·leetcode·职场和发展
Mos_x21 分钟前
计算机组成原理核心知识点梳理
java·后端
墨寒博客栈24 分钟前
Linux基础常用命令
java·linux·运维·服务器·前端
回忆是昨天里的海29 分钟前
k8s-部署springboot容器化应用
java·容器·kubernetes
INFINI Labs41 分钟前
使用 Docker Compose 轻松实现 INFINI Console 离线部署与持久化管理
java·docker·eureka·devops·docker compose·console·easyserach
Cosolar42 分钟前
国产麒麟系统 aarch64 架构 PostgreSQL 15 源码编译安装完整教程
java·后端
GalaxyPokemon1 小时前
PlayerFeedback 插件开发日志
java·服务器·前端
天天摸鱼的java工程师1 小时前
别再写那些重复代码了!8年Java老兵教你用 Hutool 提升开发效率
java·后端
喝杯绿茶1 小时前
springboot中的事务
java·spring boot·后端