【Java算法题】打印沙漏、素数对猜想、数组元素右移、双倍数、洗牌机

1. 打印沙漏

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印

*****
 ***
  *
 ***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

  • 输入格式:
    输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。

  • 输出格式:
    首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

  • 输入样例:
    19 *

  • 输出样例:

*****
 ***
  *
 ***
*****
2
  • 思路:

1)输入为正整数,且小于1000,那么至少有一个符号
2)运算:得到符号总数下,最大能用多少个数的符号构成沙漏
3)将沙漏分为两半,从只有一个符号那一层划分(该层不算上层或者下层),计算最大的组成沙漏的符号个数的同时,计算上层和下层的层数、以及沙漏整体层数
4)循环叠加计算
5)将上半层每一层的输出样式保存到数组,下层利用这个逆序输出即可
6)从上半层的最高层开始存入输出样式到数组
7)充分利用temp数组下标,因为0的时候代表最高层(对于下层就是最底层),那么就只有0个空格字符
8)准备好数组,分别输出上半层、分割层(只有一个符号)、下半层、剩余的符号个数
9)难度在于:获得沙漏的全部信息,以及输出处理

打印沙漏
  • 实现代码
import java.util.Scanner;

public class Main {

    private static void printSandglass(int src,String fuhao) {
//        if(src <= 0)题目规定src是正整数,这个判断不需要,但是一般来说最好还是有
//            return;
        int ceng = 0;//沙漏上下一半对称的层数,只有一个符号那层为分割层,不计入
        int count = 1;//沙漏最大拥有的符号数
        int max = 1;//最高层拥有的符号数
        int temp = 0;
        while((temp = count + 2 * (max + 2)) <= src) {
            //计算:假设上下各加了一层,会需要多少的符号数,是否比输入符号总数要大
            count = temp;
            ceng++;
            max += 2;
        }
        
        //上半层的输出结果存入数组
        String[] rs = new String[ceng];
        temp = 0;
        int i = 0;
        for(; temp < ceng; temp++) {//从最高层一层一层的存入
            rs[temp] = "";
            for(i = 0; i < temp; i++) {//每一层的空符号
                rs[temp] += " ";
            }
            for(i = 0; i < max; i++) {//每一次的符号
                rs[temp] += fuhao;
            }
            //每下一层就减少2个符号
            max -= 2;
        }
        
        //输出结果
        //先输出上半层
        for(i = 0; i < rs.length; i++) {
            System.out.println(rs[i]);
        }
        //输出中间只有一个符号的分割层
        while(temp > 0) {
            System.out.print(" ");
            temp--;
        }
        System.out.println(fuhao);
        //输出下半层,利用上半层的结果逆序输出
        for(i = rs.length - 1; i >= 0; i--) {
            System.out.println(rs[i]);
        }
        //输出剩余的符号数量
        System.out.println(src - count);
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        //读入数据
        while (in.hasNextInt()) {
            String str = in.nextLine();
            String[] str1 =  str.split(" ");
            //类型转换
            printSandglass(Integer.parseInt(str1[0]),str1[1]);
        }
    }
}

2. 素数对猜想

“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。

现给定任意正整数N(<10^5 ),请计算不超过N的满足猜想的素数对的个数。

  • 输入格式:
    输入在一行给出正整数N。

  • 输出格式:
    在一行中输出不超过N的满足猜想的素数对的个数。

  • 输入样例:
    20

  • 输出样例:
    4

  • 思路

1)检查数字是否为素数,如果是则判断该数字减二后,是否还为素数,如果是则计数器加一
2)输入的是正整数,从1开始
3)有一个长度为n的数组来代表n个数字,数组中第0个 代表数字1
4)因为int类型的数组的动态初始化,数组元素的值默认为0
5)从数组中第二个开始检查是否为素数,即使从数字3开始,是素数则赋值1
6)检查数组中,有可能的素数对情况,计数器计数

素数对猜想
  • 实现代码
import java.util.Scanner;

public class Main {
    //Pairs of prime guesses

    public static void pairsOfPrimeGuesses(int n) {
        int count = 0;
        //数组下标从0开始,借助数组下标表示数字,第0个下标代表数字1,以此类推
        int[] flags = new int[n];//数组代表n个数
        int i = 0;
        //判断,某个数是否为素数,是就把数组中对应位置赋值1,从数字3开始查找
        for(i = 2; i < flags.length; i++) {
            if(isPrime(i + 1)) {//如果是素数则他所在数组的代表位置赋值1
                flags[i] = 1;
//                 if(flags[i-2] == 1)//如果该数字减二之后对应的数是素数,那么就存在一对素数对
//                     count++;
            }
        }
        //检查素数对成立的条件
       for(i -= 1; i > 3; i--) {
           if(flags[i] == 1 && flags[i - 2] == 1) {
               count++;
           }
       }

        //方法二:从第n个数开始找,直到n小于5就不找,
        //这方法重复的步骤太多,不建议使用
//      while(n > 4) {
//          if(isPrime(n) && isPrime(n-2))
//              count++;
//          n--;
//      }
        System.out.println(count);

    }
    //判断是否为素数
    public static boolean isPrime(int n){
        if (n <= 3) {
            return n > 1;
        }

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

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while(in.hasNext()) {
            pairsOfPrimeGuesses(in.nextInt());
        }
    }

}

3. 数组元素循环右移问题

一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A0 A1 ⋯AN−1 )变换为(AN−M ⋯AN−1 A0 A1 ⋯AN−M−1 )(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

  • 输入格式:
    每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0);第2行输入N个整数,之间用空格分隔。

  • 输出格式:
    在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

  • 输入样例:
    6 2
    1 2 3 4 5 6

  • 输出样例:
    5 6 1 2 3 4

  • 思路

通过手动在纸上 模拟移动,发现
1)移动的样式就只有数组长度的个数,所以m的有效值在大于0小于n,输入比n大的取余数
2)m大于或者小于n的一半也有学问,可分为正序移动或者逆序移动
3)。。。难以描述,建议画一画

数组元素循环右移问题
  • 代码实现
import java.util.Scanner;

public class Main {

    public static void rotateRight(int m,String[] src) {
        m = m % src.length;
        String temp = "";
        if(m < src.length / 2) {
            int i = src.length - m - 1;
            while(i >= 0) {
                temp = src[i + m];
                src[i + m] = src[i];
                src[i] = temp;
                i--;
            }
        } else {
            int i = src.length - m;
            m = i;
            while(i < src.length) {
                temp = src[i - m];
                src[i - m] = src[i];
                src[i] = temp;
                i++;
            }
        }
        for(m = 0; m < src.length - 1; m++){
            System.out.print(src[m]+" ");
        }
        System.out.print(src[m]);
    }

    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Scanner in = new Scanner(System.in);
        int m = 0;
        String temp = null;
        String[] src = null;
        while(in.hasNext()) {
            temp = in.nextLine();
            src = temp.split(" ");
            m = Integer.parseInt(src[1]);
            temp = in.nextLine();
            rotateRight(m,temp.split(" "));
        }
    }

}

4. 与数字玩得开心

请注意,数字 123456789 是一个 9 位数字,完全包含从 1 到 9 的数字,没有重复。双倍,我们将获得246913578,这恰好是另一个9位数字,完全由数字从1到9,只是在不同的排列。检查,看看我们再次加倍的结果!

现在,你应该检查是否有更多的数字与此属性。也就是说,将给定数字翻倍。K数字,您要判断结果数字是否仅由原始数字中数字的置换组成。

  • 输入规格:
    每个输入包含一个测试用例。每个情况包含一个不超过 20 位数字的正整数。

  • 输出规格:
    对于每个测试用例,如果输入编号加倍,首先打印行"是",如果输入数字加倍,则给出的数字仅包含原始数字中数字的排列,如果没有,则为"否"。然后在下一行中打印双倍数字。

  • 示例输入:
    1234567899

  • 示例输出:
    Yes
    2469135798

  • 思路

1)将输入字符串转化为字符数组
2)依题意,字符串长度超过20可以直接输出NO
3)因为结果要输出两倍的结果,利用数组进行运算,这里运算借助了ACSII
5)把每一位的结果保存到原字符数组
6)运算前,将原字符数组中,对应的数字,在flag数组的下标位计数,flag保存原字符数组中出现的 0~9 数字的次数(flag数组默认全为0)
7)两倍的结果是:最后一个进位数字拼接上原字符数组内的结果
8)检查结果:遍历得到的字符数组,在flag数组把该数字对应的下标,进行减一操作,检查完字符数组的数字还要记得检查最后一个进位数字
9)遍历flag数字,检查是否都是0,全是0输入是符合题目要求的
10)不是则输出NO

与数字玩得开心
  • 实现代码
import java.util.Scanner;

public class Main {

    public static void HaveFunWithNumbers(String str) {
        char[] e = str.toCharArray();
        if(e.length > 20) {
            System.out.println("No");
        }
        int[] flag = new int[10];
        int jinwei = 0;
        char temp;
        int temprs;
        boolean f = true;
        for(int i = e.length - 1; i >= 0; i--) {
            temp = e[i];
            flag[temp - '0']++;
            temprs = jinwei + (temp -'0') * 2;
            e[i] = (char) (temprs % 10 + '0');
            jinwei = temprs / 10;
        }
        for(int i = e.length - 1; i >= 0; i--) {
            flag[e[i] - '0']--;
        }
        if(jinwei > 0)
            flag[jinwei]--;
        for(int i = flag.length - 1; f && i >= 0; i--) {
            if(flag[i] != 0)
                f = false;
        }
        if(f) {
            System.out.println("Yes");
        } else {
            System.out.println("No");
        }
        if(jinwei > 0)
            System.out.print(jinwei);
        for(int i = 0; i < e.length; i++){
            System.out.print(e[i]);
        }
    }

    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Scanner in = new Scanner(System.in);
        while(in.hasNext()) {
            HaveFunWithNumbers(in.nextLine());
        }
    }

}

5. 洗牌机

洗牌是一种用于随机化一副牌的过程。由于标准洗牌技术被视为薄弱,为了避免"内部工作",即员工通过执行不适当的洗牌与赌徒合作,许多赌场采用自动洗牌机。您的任务是模拟洗牌机。

机器根据给定的随机顺序洗牌 54 张牌,并重复多次。假定卡片组的初始状态按以下顺序排列:
S1, S2, ..., S13,
H1, H2, ..., H13,
C1, C2, ..., C13,
D1, D2, ..., D13,
J1, J2
其中"S"代表"斯佩德","H"代表"心","C"代表"俱乐部","D"代表"钻石","J"代表"小丑"。给定顺序是 [1, 54] 中不同整数的排列。如果数字在Ⅰ- 第 th 位置是J, 它意味着将卡从位置移动Ⅰ到位置J.例如,假设我们只有 5 张牌:S3、H5、C1、D13 和 J2。给定一个洗牌顺序 [4, 2, 5, 3, 1], 结果将是: J2, H5, D13, S3, C1。如果我们再次重复洗牌,结果将是:C1、H5、S3、J2、D13。

  • 输入规格:
    每个输入文件包含一个测试用例。对于每个情况,第一行包含一个正整数K (≤20),即重复时间数。然后下一行包含给定的顺序。行中的所有数字都用空格分隔。

  • 输出规格:
    对于每个测试用例,将洗牌结果打印在一行中。所有卡都用空格分隔,行的末尾不能有额外的空间。

  • 示例输入:
    2
    36 52 37 38 3 39 40 53 54 41 11 12 13 42 43 44 2 4 23 24 25 26 27 6 7 8 48 49 50 51 9 10 14 15 16 5 17 18 19 1 20 21 22 28 29 30 31 32 33 34 35 45 46 47

  • 示例输出:
    S7 C11 C10 C12 S1 H7 H8 H9 D8 D9 S11 S12 S13 D10 D11 D12 S3 S4 S6 S10 H1 H2 C13 D2 D3 D4 H6 H3 D13 J1 J2 C1 C2 C3 C4 D1 S5 H5 H11 H12 C6 C7 C8 C9 S2 S8 S9 H10 D5 D6 D7 H4 H13 C5

  • 思路

输入的一组数字是:每一次洗牌,将按顺序,将第一张牌放到输入的第一个数字代表的位置
例如上面的输入:第一张牌放到第36位,第2张牌放到第52位。k是洗牌的次数
1)先有一个牌的数组
2)洗k次,即使排k次序
3)每排一次序,就要将代表牌的数组换成这一次排好序的,以便下一次排序或者输出
4)输出注意格式就好

洗牌机
  • 代码
public class Main {

    static String[] cards = {"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "S12", "S13",
            "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "H11", "H12", "H13",
            "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11", "C12", "C13",
            "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "D11", "D12", "D13",
            "J1", "J2"};

    public static void ShufflingMachine(int k,String[] str) {
        String[] temp = new String[54];
//         boolean flag = true;
//         for(int i = 1; i <= cards.length && flag; i++) {
//             if(str[i - 1].equals(i + ""))
//                 flag = false;
//         }
//         if(flag)
//             return;
        while(k > 0) {
            for(int i = 0; i < cards.length; i++) {
                temp[Integer.parseInt(str[i]) - 1] = cards[i];
            }
//          if(cheak(cards,temp))
//                 return;
            String[] t = temp;
            temp = cards;
            cards = t;
            k--;
        }
        out(cards);
    }

    //检查元素是否有变
    public static boolean cheak(String[] cards,String[] temp) {
        for(int i = 0; i < cards.length; i++) {
            if(cards[i] == temp[i]) {
                return false;
            }
        }
        return true;
    }
    //输出结果
    public static void out(String[] cards) {
        for(int i = 0; i < cards.length - 1; i++) {
            System.out.print(cards[i] + " ");
        }
        System.out.println(cards[cards.length - 1]);
    }

    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Scanner in = new Scanner(System.in);
        while(in.hasNext()) {
            ShufflingMachine(Integer.parseInt(in.nextLine()),in.nextLine().split(" "));
        }
    }
}

你可能感兴趣的:(【Java算法题】打印沙漏、素数对猜想、数组元素右移、双倍数、洗牌机)