Java 基础算法训练

1. 移除元素

需求:

给你一个数组 nums 和一个值 val,你需要删除所有数值等于 val 的元素

举例1:

输入:nums = [3,2,2,3] val = 3

输出:nums = [2,2] 剩余2个元素

举例1:

输入:nums = [0,1,2,2,3,0,4,2] val = 2

输出:nums = [0,1,4,0,3] 剩余5个元素

思路

利用快慢针实现

代码

java 复制代码
package unit7;  
  
import java.util.Scanner;  
  
public class text1 {  
    //移除元素  
    public static void main(String[] args) {  
  
        Scanner sc = new Scanner(System.in);  
  
        int n = sc.nextInt();  
        int val = sc.nextInt();  
        int num = 0;  
  
        int[] nums = new int[n];  
        for(int i = 0; i< n; i++){  
            nums[i] = sc.nextInt();  
            if(nums[i] != val){  
                num++;  
            }  
        }  
  
        int[] ret = new int[num];  
  
        int slow = 0;  
        int fast = 0;  
  
        while(fast < n){  
            if(nums[fast] == val){  
                fast++;  
            }else{  
                ret[slow++] = nums[fast++];  
            }  
        }  
  
        for(int i = 0; i < ret.length; i++){  
            System.out.print(ret[i] + " ");  
        }  
  
  
    }  
}

2. 红包问题

需求:

给你两个整数M和N,M表示红包的总额, N表示红包的个数

现在又N个人来抽红包,每个人都是随机的,打印每个人领的红包金额

思路

本道题不是单纯随机就可以的,假设200元5个红包,直接5次随机有可能会遇到很多问题:

  1. 前面的人把钱都领完了,后面的人领不到了

  2. 5个人随机的总额不是红包总额

注意本题的几个坑:

  1. 每个人最少1分钱

  2. 每个人领完红包之后,至少预留 1 * N 分钱

第一个人:至少预留4分钱

第二个人:至少预留3分钱

第三个人:至少预留2分钱

第四个人:至少预留1分钱

  1. 最后一个人是拿剩余的总额,不随机

代码

java 复制代码
package unit7;  
  
import java.util.Random;  
import java.util.Scanner;  
  
/**  
 * 红包分配程序  
 * 该程序模拟了多个用户分配固定金额的红包场景  
 */  
public class text2 {  
  
    //看课学习  
    public static void main(String[] args){  
        // 创建Scanner对象用于接收用户输入  
        Scanner sc = new Scanner(System.in);  
  
        // 获取用户输入的金额m(元)和人数n  
        int m = sc.nextInt();  
        int n = sc.nextInt();  
  
        // 判断红包总金额是否足够分配  
        if(m*100 < n){  
  
            // 金额不足时提示用户充值  
            System.out.println("红包金额不足,请充值~");  
            return; // 终程序执行  
        }  
  
        // 创建随机数生成器  
        Random r = new Random();  
  
        // 将金额转换为分(单位:分)  
        int mm =  m*100;  
  
        // 循环分配红包,前n-1个人  
        for(int i = 1; i < n; i++){  
            // 生成随机金额(确保剩余金额足够分配)  
            int num = r.nextInt(mm-(n-i))+1;  
            // 输出当前用户领取的金额(转换为元)  
            System.out.printf("第%d个人领取了%.2f元\n", i, num*0.01);  
            // 减去已分配的金额  
            mm -= num;  
        }  
  
        // 最后一个人领取剩余的全部金额  
        System.out.printf("第%d个人领取了%.2f元\n", n, mm*0.01);  
    }  
}

3. 中位数

给定两个正序数组 arr1和 arr2,请先合并数组,并找出合并之后数组的中位数。

举例:

1 2 3 4 5 6 7 8 9 中位数:5

1 2 3 4 5 6 中位数: ( 3 + 4 ) / 2

思路

排序

代码

java 复制代码
package unit7;  
  
import java.util.Scanner;  
  
import static java.util.Arrays.sort;  
  
/**  
 * 合并两个数组并找出中位数的程序  
 * 该程序通过用户输入两个数组,合并后排序,最后计算并输出中位数  
 */  
public class text3 {  
    /**  
     * 主方法,用于执行程序逻辑  
     */  
    static void main() {  
        //合并两个数组并找出中位数  
  
        // 创建Scanner对象用于接收用户输入  
        Scanner sc = new Scanner(System.in);  
  
        // 提示用户输入第一个数组的长度  
        System.out.println("请输入第一个数组的长度:");  
        // 读取第一个数组的长度  
        int n1 = sc.nextInt();  
        // 创建第一个数组  
        int[] arr1 = new int[n1];  
        // 提示用户输入第一个数组的内容  
        System.out.println("请输入第一个数组:");  
        // 循环读取第一个数组的元素  
        for(int i = 0; i < n1; i++) arr1[i] = sc.nextInt();  
  
        // 提示用户输入第二个数组的长度  
        System.out.println("请输入第二个数组的长度:");  
        // 读取第二个数组的长度  
        int n2 = sc.nextInt();  
        // 创建第二个数组  
        int[] arr2 = new int[n2];  
        // 提示用户输入第二个数组的内容  
        System.out.println("请输入第二个数组:");  
        // 循环读取第二个数组的元素  
        for(int i = 0; i < n2; i++) arr2[i] = sc.nextInt();  
  
        // 创建合并后的数组,长度为两个数组长度之和  
        int[] arr = new int[n1 + n2];  
        // 将第一个数组的元素复制到合并数组中  
        for(int i = 0; i < n1; i++) arr[i] = arr1[i];  
        // 将第二个数组的元素复制到合并数组中  
        for(int i = 0; i < n2; i++) arr[n1 + i] = arr2[i];  
  
        // 对合并后的数组进行排序  
        sort(arr);  
  
        // 输出中位数结果提示信息  
        System.out.println("合并后的数组的中位数为:");  
        if((n1 + n2) % 2 == 0) System.out.println((arr[(n1 + n2) / 2 - 1] + arr[(n1 + n2) / 2]) / 2.0);  
        else System.out.println(arr[(n1 + n2) / 2]);  
    }  
}

4. 统计个数

学校选举学生会主席,有5个候选人

全校1000名同学参与投票(每人一票,可以弃权,或者选1-5号)。

投票使用Random模拟。0:弃权,1 ~ 5:给对应的候选人投票

要求1:

统计每个候选人的得票数和得票率,找出得票最多的候选人?

要求2:

统计弃票数和弃票率是多少?

思路

模拟即可

代码

java 复制代码
package unit7;  
  
import java.util.Random;  
  
/**  
 * 这是一个模拟投票程序的类,用于统计5个候选人的得票情况以及弃票情况  
 */  
public class text4 {  
    /**  
     * 主方法,用于执行投票统计逻辑  
     */  
    static void main() {  
  
        int people = 5;    // 候选人数量  
        int student = 1000; // 总投票人数  
  
        // 创建一个长度为6的数组,用于存储0-5号选项的票数(0代表弃票,1-5代表候选人)  
        int[] num = new int[6];  
  
        // 创建随机数生成器  
        Random r = new Random();  
        // 循环模拟1000人投票  
        for(int i = 0; i < student; i++) {  
            // 生成0-5之间的随机数,模拟投票选择  
            int n = r.nextInt(6);  
            // 对应选项的票数加1  
            num[n]++;  
        }  
  
        // 遍历1-5号候选人,输出各自的得票数和得票率  
        for(int i= 1; i <= 5; i++){  
            //输出得票数与得票率,保留两位小数  
            System.out.printf("第%d号得票数:%d,得票率:%.2f%%\n", i, num[i], num[i] * 100.0 / student);  
        }  
  
        //输出弃票数与弃票率  
        System.out.printf("弃票数:%d,弃票率:%.2f%%\n", num[0], num[0] * 100.0 / student);  
    }  
}

5. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]

输出:6

代码

java 复制代码
package unit7;  
  
import java.util.Scanner;  
  
import static java.lang.Math.min;  
  
//给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水  
//运用动态规划的思想  
  
public class text5 {  
    /**  
     * 主方法,用于计算接雨水的总量  
     */  
    static void main() {  
  
        // 创建Scanner对象用于读取用户输入  
        Scanner sc = new Scanner(System.in);  
        // 读取数组长度n  
        int n = sc.nextInt();  
        // 创建长度为n的数组arr用于存储高度值  
        int[] arr = new int[n];  
        // 循环读取n个高度值存入数组arr  
        for (int i = 0; i < n; i++) arr[i] = sc.nextInt();  
          
          
        // 创建left数组用于存储每个位置左边的最大值  
        int[] left = new int[n];  
        // 创建right数组用于存储每个位置右边的最大值  
        int[] right = new int[n];  
          
        // 初始化left数组的第一个元素  
        left[0] = arr[0];  
        // 初始化right数组的最后一个元素  
        right[n - 1] = arr[n - 1];  
          
        // 从左向右遍历,计算每个位置左边的最大值  
        for (int i = 1; i < n; i++){  
            left[i] = max(left[i - 1], arr[i]);  
        }  
        // 从右向左遍历,计算每个位置右边的最大值  
        for (int i = n - 2; i >= 0; i--) {  
            right[i] = max(right[i + 1], arr[i]);  
            }  
          
        // 初始化总和为0  
        int sum = 0;  
        // 计算每个位置能接到的雨水量并累加到sum中  
        for (int i = 0; i < n; i++) {  
            sum += min(left[i], right[i]) - arr[i];  
        }  
          
        // 输出总雨水量  
        System.out.println(sum);  
        }  
    /**  
     * 辅助方法,返回两个整数中的较大值  
     * a 第一个整数  
     * b 第二个整数  
     * a和 b中的较大值  
     */  
    static int max(int a, int b) {  
        return a > b ? a : b;  
    }  
      
}

6. 大乐透

需求:

号码介绍:

大乐透选号规则明确规定:同一投注区内的号码不可重复,但不同投注区之间允许号码重复。具体规则可分为前区和后区两个维度:

大乐透选号重复规则详解

1.前区号码不可重复。

  • 投注范围:从01-35中选择5个号码。

  • 规则要求:所选5个号码之间不可出现重复数字,如出现重复则该注视为无效投注。

2.后区号码不可重复。

  • 投注范围:从01-12中选择2个号码。

  • 规则要求:所选2个号码之间不可重复,否则同样视为无效投注。跨区重复规则。

前区与后区号码允许交叉重复,例如前区选10,后区也可选10。系统自动判定:跨区重复不会触发错误提示,属于有效投注。

玩法知识延伸

基本结构:采用"5+2"双区投注模式,前区35选5与后区12选2组合形成完整投注号码。

无效投注判定:同一区内重复号码在开奖前会被系统自动识别为无效票,无法参与兑奖。

策略提醒:虽然跨区重复有效,但统计显示前区与后区号码重复率仅3.8%,建议选号时优先考虑号码分布合理性。

中奖规则:

代码

java 复制代码
package unit7;  
  
import java.util.Random;  
import java.util.Scanner;  
  
public class text6 {  
  
    /*  
    * 彩票规则:  
    * 前区: 1~35 选5个号码(唯一)  
    * 后区: 1~12 选2个号码(唯一)  
    * 跨区域可重复  
    *    * 中奖规则:  
    * 一等奖: 5+2  
    * 二等奖: 5+1  
    * 三等奖: 5+0/4+2  
    * 四等奖: 4+1/3+2  
    * 五等奖: 4+0/3+1/2+2  
    * 六等奖: 3+0/2+1/1+2/0+2  
    *    * 1. 利用Random随机, 生成彩票号码  
    * 2. 利用Scanner模拟购买彩票  
    * 3. 判断中奖  
    * */    static void main() {  
  
        //1. 利用Random随机, 生成彩票号码  
        int[] lotteryNumber = creatLotteryNumber();  
  
        printLotteryNumber(lotteryNumber);  
  
        //2. 利用Scanner模拟购买彩票  
        int[] myLotteryNumber = buyLotteryNumber();  
  
        printLotteryNumber(myLotteryNumber);  
  
        //3. 判断中奖  
        //判断中了几个前区(红球)  
        //判断中了几个后区(蓝球)  
        //注意:与顺序无关  
        getWinnerNumber(lotteryNumber, myLotteryNumber);  
  
    }  
  
    //arr1为彩票号码, arr2为购买号码  
    public static void getWinnerNumber(int[] arr1, int[] arr2){  
        int count = 0;  
        //前区  
        count = getCount(arr2[0], arr1, 0, 4);  
  
        System.out.println("中了" + count + "个红球");  
  
        //后区  
        int count2 = 0;  
        count2 = getCount(arr2[5], arr1, 5, 6);  
  
        System.out.println("中了" + count2 + "个蓝球");  
  
        //判断中奖  
        if(count == 5 && count2 == 2){  
            System.out.println("恭喜你中了一等奖");  
        }else if((count == 5 && count2 == 1) || (count == 4 && count2 == 2)){  
            System.out.println("恭喜你中了二等奖");  
        }else if((count == 5 && count2 == 0) || (count == 4 && count2 == 0) || (count == 4 && count2 == 1) || (count == 3 && count2 == 2)){  
            System.out.println("恭喜你中了三等奖");  
        }else if((count == 4 && count2 == 0) || (count == 3 && count2 == 1) || (count == 3 && count2 == 0) || (count == 2 && count2 == 2) || (count == 1 && count2 == 2) || (count == 0 && count2 == 2)){  
            System.out.println("恭喜你中了四等奖");  
        }else if((count == 4 && count2 == 0) || (count == 3 && count2 == 1) || (count == 3 && count2 == 0) || (count == 2 && count2 == 2) || (count == 1 && count2 == 2) || (count == 0 && count2 == 2)){  
            System.out.println("恭喜你中了五等奖");  
        }else if((count == 3 && count2 == 0) || (count == 2 && count2 == 1) || (count == 1 && count2 == 2) || (count == 0 && count2 == 2)){  
            System.out.println("恭喜你中了六等奖");  
        }else if(count == 0 && count2 == 0){  
            System.out.println("恭喜你,没有中奖");  
        }  
    }  
  
    //判断前区或后区中了几个球  
    public static int getCount(int number, int[] arr, int start, int end){  
        int count = 0;  
  
        for (int i = start; i <= end; i++) {  
            boolean flag = contains(number, arr, start, end);  
            if(flag){  
                count++;  
            }  
        }  
  
        return count;  
    }  
  
    public static int[] buyLotteryNumber(){  
        //1.创建数组  
        int[] arr = new int[7];  
  
        //2.利用Scanner, 生成前区彩票号码  
        Scanner sc = new Scanner(System.in);  
        for (int i = 0; i < 5; ) {  
            System.out.println("请输入第" + (i+1) + "个前区号码(1~35):");  
            int number = sc.nextInt();  
            //范围判断  
            if (number < 1 || number > 35){  
                System.out.println("当前彩票号码不在范围当中,请重新选择");  
                continue;  
            }  
            //判断number是否唯一  
            boolean flag = contains(number, arr, 0 , 4);  
            if(flag){  
                System.out.println("当前彩票号码重复,请重新选择");  
                continue;  
            }  
            if(!flag) {  
                arr[i] = number;  
                i++;  
            }  
  
        }  
  
        //3.利用Scanner, 生成后区彩票号码  
        for (int i = 5; i < arr.length; ) {  
            System.out.println("请输入第" + (i+1) + "个后区号码(1~12):");  
            int number = sc.nextInt();  
            //范围判断  
            if (number < 1 || number > 12){  
                System.out.println("当前彩票号码不在范围当中,请重新选择");  
                continue;  
            }  
            //判断number是否唯一  
            boolean flag = contains(number, arr, 5, 6);  
            if(flag){  
                System.out.println("当前彩票号码重复,请重新选择");  
                continue;  
            }  
            if(!flag) {  
                arr[i] = number;  
                i++;  
            }  
        }  
  
        return arr;  
    }  
  
    public static int[] creatLotteryNumber(){  
        //1.创建数组  
        int[] arr = new int[7];  
  
        //2.利用Random随机, 生成前区彩票号码  
        Random r = new Random();  
        for (int i = 0; i < 5; ) {  
            int number = r.nextInt(1,36);  
            //判断number是否唯一  
            boolean flag = contains(number, arr, 0 , 4);  
            if(!flag){  
                arr[i] = number;  
                i++;  
            }  
        }  
  
        //3.利用Random随机, 生成后区彩票号码  
        for (int i = 5; i < arr.length; ) {  
            int number = r.nextInt(1,13);  
            //判断number是否唯一  
            boolean flag = contains(number, arr, 5, 6);  
            if(!flag){  
                arr[i] = number;  
                i++;  
            }  
  
        }  
  
  
  
        return arr;  
    }  
  
    public static boolean contains(int number, int[] arr, int start, int end){  
        for (int i = start; i <= end; i++) {  
            if (number == arr[i]){  
                return true;  
            }  
        }  
        return false;  
    }  
  
    public static void printLotteryNumber(int[] arr){  
        for (int i = 0; i < arr.length; i++) {  
            System.out.print(arr[i] + " ");  
        }  
        System.out.println();  
  
    }  
}
相关推荐
map1e_zjc2 小时前
Java SpringBoot学习记录(4)
java·开发语言·学习
小毛驴8502 小时前
多线程同步打标记的几种实现方案
java·开发语言·python
Mr_Xuhhh2 小时前
递归之美:合并两个有序链表的优雅解法
java·开发语言
门左有棵树2 小时前
蓝桥杯C++组算法知识点整理(考前急救)
c++·算法·蓝桥杯
bluebonnet272 小时前
【Python】一些PEP提案(五):注解的延迟求值
开发语言·python
橙露2 小时前
Python 操作 MongoDB:非关系型数据查询与分析
开发语言·python·mongodb
小魏小魏我们去那里呀2 小时前
Java2Flowchart:一款把 Java 方法一键转换成 Mermaid 流程图的 IntelliJ 插件
java·ide·intellij-idea
小江的记录本2 小时前
【RAG】RAG检索增强生成(核心架构、全流程、RAG优化方案、常见问题与解决方案)
java·前端·人工智能·后端·python·机器学习·架构
历程里程碑2 小时前
二叉树---二叉树的最大深度
大数据·数据结构·算法·elasticsearch·搜索引擎·全文检索·深度优先