【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(" "));
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容