1. 程式人生 > >JAVA入門演算法題(三)

JAVA入門演算法題(三)

把敬業變成習慣。短期來看是為了僱主,長期來看是為了自己。

1.題目:輸入一行字元,分別統計出其中英文字母、空格、數字和其它字元的個數。

估計統計字元是所有人都做過的題

這裡給出兩種思路,第一種思路是比較ASCII碼,第二種是使用正則匹配

private static void Method1() {
        int letter=0;
        int space=0;
        int number=0;
        int other=0;
        Scanner scanner=new Scanner(System.in);
        String string=scanner.nextLine();
        char[] chars=string.toCharArray();
        for (char i:chars){
            if ('0'<=i&&i<='9'){
                number++;
            }else if (('a'<=i&&i<='z')||('A'<=i&&i<'Z')){
                letter++;
            }else if (' '==i){
                space++;
            }else {
                other++;
            }
        }
        System.out.println("字元個數:"+letter+" 空格個數:"+space+" 數字個數:"+number+" 其他個數:"+other);
    }
private static void Method2() {
        String E1 = "[a-zA-Z]";//字母
        String E2 = "[0-9]";//數字
        String E3 = "\\s";//空格
        int letter=0;
        int space=0;
        int number=0;
        int other=0;
        Scanner scanner=new Scanner(System.in);
        String string=scanner.nextLine();
        String[] strings=string.split("");
        for (String s:strings){
            if (s.matches(E1)){
                letter++;
            }else if (s.matches(E2)){
                number++;
            }else if (s.matches(E3)){
                space++;
            }else {
                other++;
            }
        }
        System.out.println("字元個數:"+letter+" 空格個數:"+space+" 數字個數:"+number+" 其他個數:"+other);
    }

2.題目:兩個乒乓球隊進行比賽,各出三人。甲隊為a,b,c三人,乙隊為x,y,z三人。已抽籤決定比賽名單。 有人向隊員打聽比賽的名單。a說他不和x比,c說他不和x,z比,請程式設計找出三隊賽手的名單。

這道題也是一道非常經典的問題,主要考察全排列的思維,隨後篩除

我的第一種解法可能和大家都不一樣,個人非常喜歡操作字串,我於是把所有情況遍歷出來,然後使用reolace方法替換掉不符合條件的情況

List<String> yi=Arrays.asList("X","Y","Z");
        List<String> duilie=new ArrayList<>();
        for (int i=0;i<yi.size();i++){
            for (int j=0;j<yi.size();j++){
                for (int k=0;k<yi.size();k++){
                    if (j!=i&&k!=j&k!=i){
                        duilie.add("A:"+yi.get(i)+",B:"+yi.get(j)+",C:"+yi.get(k));
                    }
                }
            }
        }
        System.out.println(duilie);
        for (String s:duilie){
            int length=s.length();
            s=s.replace("A:X","").replace("C:Z","").replace("C:X","");
            if (s.length()==length){
                System.out.println(s);
            }
        }

第二種解法就是大家都能想到的for迴圈巢狀,if篩選了

char a, b, c;
        for (a = 'x'; a <= 'z'; a++) {
            for (b = 'x'; b <= 'z'; b++) {
                if (a != b) {
                    for (c = 'x'; c <= 'z'; c++) {
                        if (a != c && b != c) {
                            if (a != 'x' && c != 'x' && c != 'z') {
                                System.out.println("A的對手是" + a);
                                System.out.println("B的對手是" + b);
                                System.out.println("C的對手是" + c);
                            }
                        }

                    }
                }
            }
        }

3.題目:一個偶數總能表示為兩個素數之和。

(注:哥德巴赫猜想:任一大於2的偶數都可寫成兩個質數之和。)

我是採用的這樣的思路,先對這個數找到所有該範圍的素數,然後迴圈如果這個數減去範圍內一個素數的結果是一個宿舍的話就證明是對的,之前找素數和驗證素數的思路都有說過

 private static void Method1() {
        Scanner scanner=new Scanner(System.in);
        int number=scanner.nextInt();
        List<Integer> integerList=getPrimeNumber(number);
        for (int i=0;i<integerList.size();i++){
            if (integerList.get(i)>number/2){
                break;
            }
            if (isPerimeNumber(number-integerList.get(i))){
                System.out.println(number+"="+integerList.get(i)+"+"+(number-integerList.get(i)));
            }
        }
    }

    private static boolean isPerimeNumber(int number) {
        int j=0;
        int k=0;
        for (int i=2;i<=number;i++){
            k=(int)sqrt(i+1);
            for (j=2;j<=k;j++){
                if (i%j==0){
                    break;
                }
            }
            if (j==k+1){
                return true;
            }
        }
        return false;
    }

    private static List<Integer> getPrimeNumber(int number) {
        List<Integer> integerList=new ArrayList<>();
        int j=0;
        int k=0;
        for (int i=2;i<=number;i++){
            k=(int)sqrt(i+1);
            for (j=2;j<=k;j++){
                if (i%j==0){
                    break;
                }
            }
            if (j==k+1){
                integerList.add(i);
            }
        }
        return integerList;
    }

4.題目:有n個人圍成一圈,順序排號。從第一個人開始報數(從1到3報數), 凡報到3的人退出圈子,問最後留下的是原來第幾號的那位。

這樣的問題統稱為約瑟夫環,是一種很有意思的題,如果你之前看過我寫的python入門演算法題的話用java實現的思路也是一樣的。

做這道題一共三個步驟,首先先把能報到3的人新增到一個列表裡面,然後統一移除,最後把最後幾個沒報數的人放到列表前面,重複上述步驟直到人數為2,然後把輸出第二個人,因為兩個人數3,出去的肯定是第一個

注意一下我用的列表CopyOnWriteArrayList,如果你使用普通的arraylist你就會遇到一個錯誤,叫做執行時修改錯誤,就是告訴你你不能對這個列表有增減操作時獲取它的資訊,使用CopyOnWriteArrayList可以避免這個錯誤

private static void Method1() {
        CopyOnWriteArrayList<Integer> integerList = new CopyOnWriteArrayList();
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        for (int i = 1; i <= n; i++) {
            integerList.add(i);
        }
        while (integerList.size()>2){
            int y=integerList.size()%3;
            CopyOnWriteArrayList<Integer> integers=new CopyOnWriteArrayList();
            for (int i=1;i<integerList.size()/3+1;i++){
                integers.add(integerList.get(3*i-1));
            }
            System.out.println("移除:"+integers);
            integerList.removeAll(integers);
            integerList=move(integerList,y);
        }
        System.out.println(integerList.get(1));
    }

    private static CopyOnWriteArrayList<Integer> move(CopyOnWriteArrayList<Integer> integerList, int y) {
        CopyOnWriteArrayList<Integer> integers=new CopyOnWriteArrayList<>();
        integers.addAll(integerList.subList(integerList.size()-y,integerList.size()));
        integers.addAll(integerList.subList(0,integerList.size()-y));
        System.out.println("拼接:"+integerList.subList(integerList.size()-y,integerList.size())+"    "+integerList.subList(0,integerList.size()-y));
        return integers;
    }

當然還有另一種思路,我們可以讓這個圈的人數到三的掛個牌,告訴其它人我已經出局了,別搭理我了,而不是走出這個圈。

每當下標等於人數時就把下標置零,這樣實現迴圈數數。不斷迴圈直到存活人數為1時退出迴圈,找到沒掛牌的那個人,輸出

 private static void Method2() {
        System.out.println("請輸人數n:");
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        boolean[] arr = new boolean[n];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = true; //下標為TRUE時說明還在圈裡
        }
        int leftCount = n;
        int countNum = 0;
        int index = 0;
        while (leftCount > 1) {
            if (arr[index] == true) { //當在圈裡時
                countNum++;  //報數遞加
                if (countNum == 3) { //報數為3時
                    countNum = 0; //從零開始繼續報數
                    arr[index] = false; //此人退出圈子
                    for (int i = 0; i < n; i++) {
                        System.out.print(arr[i]+" ");
                    }
                    System.out.println();
                    leftCount--; //剩餘人數減一
                }
            }
            index++; //每報一次數,下標加一
            if (index == n) { //是迴圈數數,當下標大於n時,說明已經數了一圈,
                index = 0; //將下標設為零重新開始。
            }
        }
        for (int i = 0; i < n; i++) {
            if (arr[i] == true) {
                System.out.println(i+1);
            }
        }
    }