编程习题集1

本文涵盖了多种算法问题的解决方案,包括计算糖果的数量、寻找数组中出现次数超过一半的数、避免数字2、求最小公倍数、数组元素删除策略、找出最小的k个数、计算阶乘末尾0的数量、数字反转、斐波那契数列计算及机器人行走路径。这些算法涉及数学、数据结构和搜索策略,展示了在不同场景下的计算和优化技巧。
摘要由CSDN通过智能技术生成

1、计算糖果

A,B,C三个人是好朋友,每个人手里都有一些糖果,我们不知道他们每个人手上具体有多少个糖果,但是我们知道以下的信息:
A - B, B - C, A + B, B + C. 这四个数值.每个字母代表每个人所拥有的糖果数.
现在需要通过这四个数值计算出每个人手里有多少个糖果,即A,B,C。这里保证最多只有一组整数A,B,C满足所有题设条件。

输入:输入为一行,一共4个整数,分别为A - B,B - C,A + B,B + C,用空格隔开。 范围均在-30到30之间(闭区间)。
输出:输出为一行,如果存在满足的整数A,B,C则按顺序输出A,B,C,用空格隔开,行末无空格。 如果不存在这样的整数A,B,C,则输出No

//需要注意的是:输入时整数,输出也需要时整数,如果说输出不是整数,那就是没有解,应该输出no
//而java在做除法的时候,除数和被除数都是int,结果也就是int,就会导致无法确定这个解到底是不是整数,因此需要使用精度类型
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextInt()) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            int c = scanner.nextInt();
            int d = scanner.nextInt();
			
			//根据题目中的公式先表达出每人手中的糖果
            float A=(a+c)/2f;
            float B=(c-a)/2f;
            float C=(d-b)/2f;
            if((A-((a+c)/2))!=0){
                System.out.print("No");
                return ;
            }
            if((B-((c-a)/2)!=0)||(B!=((b+c)/2))){
                System.out.print("No");
                return ;
            }
            if((C-((d-b)/2))!=0){
                System.out.print("No");
                return ;
            }
            System.out.print((int)A+" "+(int)B+" "+(int)C);
        }
    }

2、n个数中出现次数大于等于n/2的数

输入n个整数,输出出现次数大于等于数组长度一半的数。
输入:每个测试输入包含 n个空格分割的n个整数,n不超过100,其中有一个整数出现次数大于等于n/2。
输出:输出出现次数大于等于n/2的数。

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<String,Integer> map = new HashMap<>();
        String[] nums = new String[1000];
        while (scanner.hasNext()) {
            String str = scanner.nextLine();
            nums = str.split(" ");

            for(String i : nums) {
                Integer value = map.get(i);
                if(value == null) {
                    map.put(i,1);
                }else {
                    map.put(i,value+1);
                }
            }

            for(HashMap.Entry<String,Integer> entry : map.entrySet()) {
                if(entry.getValue() >= nums.length / 2) {
                    System.out.println(entry.getKey());
                }
            }
        }
    }

3、不要二

二货小易有一个W*H的网格盒子,网格的行编号为0H-1,网格的列编号为0W-1。每个格子至多可以放一块蛋糕,任意两块蛋糕的欧几里得距离不能等于2。
小易想知道最多可以放多少块蛋糕在网格盒子里。
输入描述:每组数组包含网格长宽W,H,用空格分割.(1 ≤ W、H ≤ 1000)
输出描述:输出一个最多可以放的蛋糕数

在这里插入图片描述

 public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int col = in.nextInt();
        int row = in.nextInt();
        int[][] grid = new int[row][col];

//把所有可以放蛋糕的数组内容都设为1
        for(int i = 0; i < row; i++){
            if(i % 4 == 0 || i % 4 == 1){
                for(int j = 0; j < col; j++){
                    if(j % 4 == 0 || j % 4 == 1){
                        grid[i][j] = 1;
                    }
                }
            }
            else {
                for(int j = 0; j < col; j++){
                    if(j % 4 == 2 || j % 4 == 3){
                        grid[i][j] = 1;
                    }
                }
            }
        }

        int count = 0;
        for(int x = 0; x < row; x++){
            for(int y = 0; y < col; y++){
                if(grid[x][y] == 1){
                    count++;
                }
            }
        }

        System.out.println(count);
    }

4、求最小公倍数

正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。
最小公倍数=(a*b) / 最大公约数
最大公约数:

  1. a/b,令r为所得余数(0≤r<b) 若r=0,算法结束,a即为答案
  2. 互换:置 a←b,b←r,并返回第一步
public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int a =scanner.nextInt();
        int b = scanner.nextInt();
        System.out.println(lcm(a,b));
    }

    //最小公倍数 = (a*b)/最大公约数
    private static int lcm(int a, int b) {
        return (a * b) / gcd(a,b);
    }

    //求最大公约数
    private static int gcd(int a, int b) {
        if(b == 0) {
            return a;
        }
        return gcd(b,a % b);
    }

5、删数

有一个数组a[N]顺序存放0~N-1,要求每隔两个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。以8个数(N=7)为例:{0,1,2,3,4,5,6,7},0->1->2(删除)->3->4->5(删除)->6->7->0(删除),如此循环直到最后一个数被删除。
输入描述:
每组数据为一行一个整数n(小于等于1000),为数组成员数,如果大于1000,则对a[999]进行计算。
输出描述:
一行输出最后一个被删掉的数的原始下标位置。

解题思路:可以将输入的数直接放在List中,题目中要求每隔两个数字就删除掉一个,从0号下标开始算起,2号下标就应该删除掉。使用(i+2)%size,来找到需要删除的下标

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            if(n > 1000) {
                n = 999;
            }
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                list.add(i);
            }
            int i = 0;
            while (list.size() > 1) {
                i = (i + 2) % list.size();
                list.remove(i);
            }
            System.out.println(list.get(0));
        }
    }

6、n个数中最小的k个

输入描述:每个测试输入包含空格分割的n+1个整数,最后一个整数为k值,n不超过100。
输出描述:输出n个整数里最小的k个数。升序输出

(1)直接使用Arrays.sort()方法

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String line = scanner.nextLine();
            String[] arr = line.split(" ");
            int[] arr1 = new int[arr.length-1];
            for (int i = 0; i < arr.length-1; i++) {
                arr1[i] = Integer.parseInt(arr[i]);
            }
            Arrays.sort(arr1);
            int n = Integer.parseInt(arr[arr.length-1]);
            for (int i = 0; i < n; i++) {
                System.out.print(arr1[i] + " ");
            }
        }
    }

(2)使用快速排序

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str = sc.nextLine();
            String[] a = str.split(" ");
            int[] num = new int[a.length-1];
            for (int i = 0; i < a.length-1; i++) {
                num[i] = Integer.parseInt(a[i]);
            }

            int k = Integer.parseInt(a[a.length-1]);//a中的最后一个元素
            int start = 0;
            int end = num.length-1;
            int index = qSort(num,start,end);
            while (index != k) {
                if(index > k) {
                    end = index - 1;
                    index = qSort(num,start,end);
                }else {
                    start = index + 1;
                    index = qSort(num,start,end);
                }
            }
            Arrays.sort(num,0,k);
            for (int i = 0; i < k; i++) {
                System.out.print(num[i] + " ");
            }
        }
    }

    private static int qSort(int[] num, int start, int end) {
        int dig = num[start];//基准值
        while (start < end) {
            while (start < end && num[end] >= dig) {
                end--;
            }
            num[start] = num[end];
            while (start < end && num[start] < dig) {
                start++;
            }
            num[end] = num[start];
        }
        num[start] = dig;
        return start;
    }

7、末尾0的个数

输入一个正整数n,求n!(即阶乘)末尾有多少个0
输入:输入为一行,n(1 ≤ n ≤ 1000)
输出:输出一个整数
(1)直接使用%10的办法来计算,但是这个方法如果阶乘数字很大就会导致越界。

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int sum = 0;
        while (scanner.hasNext()) {
            double n = scanner.nextInt();
            for (double i = n-1; i > 0; i--) {
                n = n * i;
            }

            while (n % 10 == 0) {
                sum++;
                n = n/10;
            }

            System.out.println(sum);
        }
    }

(2)这里可以想象最后阶乘的数字,任何一个数字都可以由小于或等于自己的数字分解而成,而阶乘最后求得的数字是一个特殊的分解。因此末尾为0的个数实际就是2*5的个数,2的个数明显是很多的,因此问题就转化成求5的个数。但是5的倍数中也有5的这个因数,需要特殊处理。

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int res = 0;
        for (int i = n; i >= 5; i--) {
            int tmp = i;
            while (tmp % 5 == 0) {
                res++;
                //处理5的倍数的情况
                tmp = tmp / 5;
            }
        }
        System.out.println(res);
    }

8、数字颠倒

输入一个整数,将这个整数以字符串的形式逆序输出程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001

输入:输入一个int整数
输出:将整个整数逆序输出
(1)StringBuilder中reverse()方法

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        String str = n +"";
        StringBuilder sb = new StringBuilder(str);
        sb.reverse();
        System.out.println(sb.toString());
    }

(2)%10/10

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        if(n == 0) {
            System.out.println(0);
        }
        while (n != 0) {
            int t = n % 10;
            n = n / 10;
            System.out.print(t);
        }
    }

9、Fibonacci数列

Fibonacci数列是这样定义的:
F[0] = 0
F[1] = 1
for each i ≥ 2: F[i] = F[i-1] + F[i-2]
因此,Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, …,在Fibonacci数列中的数我们称为Fibonacci数。给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1,现在给你一个数N求最少需要多少步可以变为Fibonacci数。

输入描述:输入为一个正整数N(1 ≤ N ≤ 1,000,000)
输出描述:输出一个最小的步数变为Fibonacci数

(1)直接将1000000个斐波那契数存入到数组中,查看输入的n在哪个区间范围,直接求最小的步数。

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[] fiboncci = new int[1000000];
        fiboncci[0] = 0;
        fiboncci[1] = 1;
        for (int i = 2; i < fiboncci.length; i++) {
            fiboncci[i] = fiboncci[i-1] + fiboncci[i-2];
        }

        int n = sc.nextInt();
        int left = 0;
        int right = 0;
        for (int i = 0; i < fiboncci.length; i++) {
            if(n == fiboncci[i]) {
                System.out.println(0);
                return;
            }
            if(n < fiboncci[i] && n > fiboncci[i-1]) {
                right = fiboncci[i] - n;
                left = n - fiboncci[i-1];
                if(right < left) {
                    System.out.println(right);
                    return;
                }else {
                    System.out.println(left);
                    return;
                }
            }
        }
    }

(2)斐波那契数列的规律是A(n)=A(n-1)+A(n-2),这个题目不需要我们知道整个斐波那契数列的数值,只需要比较n和前后两个数字的大小,所以我们只需要用a b c来代替A(n) A(n-1) A(n-2),如果某一项大于等于n,就停止迭代,最后计算n的值介于最后两个数字之间的距离,找出最小的即可。

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = 0;
        int a = 0,b = 1, c = 1;
        if(sc.hasNext()) {
            n = sc.nextInt();
        }
        while (c < n) {
            a = b;
            b = c;
            c = a+b;
        }
        int dis1 = n - b;
        int dis2 = c - n;
        System.out.println(dis1<dis2?dis1:dis2);
    }

10、 机器人走方格

有一个X*Y的网格,一个机器人只能走格点且只能向右或向下走,要从左上角走到右下角。请设计一个算法,计算机器人有多少种走法。

给定两个正整数int x,int y,请返回机器人的走法数目。保证x+y小于等于12。

题目中要求机器人只能向右或者向下走,如果向下走,就变成了计算(X-1)*Y网格的走法有多少。如果向右走,就变成了计算X * (Y-1)网格的走法有多少。当网格只有一行或者一列的时候,就只有一种方法

public int countWays(int x, int y) {
        if(x == 1 || y == 1) {
            return 1;
        }
        return countWays(x-1,y) + countWays(x,y-1);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值