2020年2月27日 星期四

[zerojudge]a015. 矩陣的翻轉

a015. 矩陣的翻轉

行和列的調換,[i][j] → [j][i],用巢狀for迴圈接受輸入,顛倒行列之後存進matrix中,最後照順序輸出matrix。

程式碼如下:

/* a015:矩陣的翻轉
*
* 2020/2/27
*
*/

import java.util.Scanner;

public class Pa015{

    public static void main(String [] args){
        Scanner scanner = new Scanner(System.in);

        while(scanner.hasNext()){
            int row = scanner.nextInt();
            int col = scanner.nextInt();

            int[][] matrix = new int[col][row];

            for(int i = 0; i < row; i++){
                for(int j = 0; j < col; j++){
                    matrix[j][i] = scanner.nextInt();
                }
            }

            for(int i = 0; i < col; i++){
                for(int j = 0; j < row; j++){
                    System.out.print(matrix[i][j] + " ");
                }
                System.out.println();
            }

        } 
    }

}

[zerojudge]a013. 羅馬數字

a013. 羅馬數字

這題是現在遇到最有難度的問題,不花點時間想想還真解不出來。 羅馬數字的規則:

羅馬數字 數目
I 1
V 5
X 10
L 50
C 100
D 500
M 1,000

加法規則

依據上表由大到小加起來表示數目
e.g.
  • 1 = I
  • 3 = III
  • 5 = V
  • 7 = VII
  • 110 = CX

減法規則

依據上表由小到大組成,表示大數目減小數目,遇到4、9時適用
e.g.
  • 4 = 5 - 1 = IV
  • 9 = 10 - 1 = IX
  • 40 = 50 - 10 = XL
  • 99 = 90 + 9 = (100 - 10) + (10 - 1) = XC + IX = XCIX
  • 110 = CX
羅馬字和整數的表格轉換成一個字串roman和整數陣列num,
roman = "IVXLCDM"
num = {1, 5, 10, 50, 100, 500, 1000}
每個字元的位置對應到num的值,num[roman.indexOf(要查詢的字元)]。


解題分兩個部份:

一、羅馬轉整數

讀入字串後依據左到右的順序,判斷是大到小還是小到大進而決定適用哪種規則。判斷的方法是字元兩個兩個比對,0號和1號比,1號和2號比…以此類推。 為了避免最後一個字元沒有可以比對的對象,在字串後面加上一個"I"。 如果是小到大即加法規則,把加進結果中。大到小就相減再加進結果。

二、整數轉羅馬

把整數的每個位數分開,像是把1998拆成{1, 9, 9, 8}接著存入陣列中。 這個簡單,只要一直除10就好。 因為羅馬數字是從大的開始書寫,所以逆向處理陣列(e.g. 1->9->9->8變成8->9->9->1),
轉換結果會有幾種:
  • 9: 10-1
  • 6~8: 5+(1~3)
  • 5: 5
  • 4: 5-1
  • 0~3: 0~3
陣列的索引(index,中文是叫做索引嗎我忘了)也代表了位數(個十百千),索引的值*2可以對應到num,個位數索引是0,對應到num的I(1), 0+1=1對應到num的V(5),0+2對應到num的X(10), 十位數索引是1,乘二=2,對應到num的X(10),2+1=3對應到num的L(50)…以此類推。

程式碼如下:

/* a013:羅馬數字
*
* 2020/2/27
*
*/

import java.util.Scanner;

public class Pa013{

    static String roman = "IVXLCDM";
    static int[] num = {1, 5, 10, 50, 100, 500, 1000};

    public static void main(String [] args){
        Scanner scanner = new Scanner(System.in);

        while(scanner.hasNext()){
            String word = scanner.next();
            if(word.equals("#")) return;
            int a = romanToInt(word);
            int b = romanToInt(scanner.next());
            System.out.println(intToRoman(Math.abs(a - b)));
        } 
    }

    public static int romanToInt(String s){
        s += "I";
        int result = 0;

        for(int i = 1; i < s.length(); i++){
            int current = num[roman.indexOf(s.charAt(i - 1))];
            int next = num[roman.indexOf(s.charAt(i))];

            if(current >= next){
                result += current;
            }else{
                i++;
                result += next - current;
            }
        } 
        return result;
    }

    public static String intToRoman(int val){
        if(val == 0) return "ZERO";

        int[] nums = new int[(int)Math.log10(val) + 1];
        String result = "";

        for(int i = 0; i < nums.length; i++){
            nums[i] = val % 10;
            val /= 10;
        }

        for(int i = nums.length - 1; i >= 0; i--){
            if(nums[i] == 9){
                result += roman.charAt(i * 2);
                result += roman.charAt(i * 2 + 2);
            }else if(nums[i] >= 5){
                result += roman.charAt(i * 2 + 1);
                for(int j = 0; j < nums[i] - 5; j++){
                    result += roman.charAt(i * 2);
                }
            }else if(nums[i] == 4){
                result += roman.charAt(i * 2);
                result += roman.charAt(i * 2 + 1);
            }else{
                for(int j = 0; j < nums[i]; j++){
                    result += roman.charAt(i * 2);
                }
            }
        }

        return result;
    }
}    

2020年2月26日 星期三

[zerojudge]a010. 因數分解

a010. 因數分解

因數分解就是從2開始除一直除到除不下去為止嘛, 迴圈結構:

        for(除數 = 2; 被除數 != 1; 除數加一){
            while(被除數可以被除數整除){
                被除數 = 被除數 / 除數;
            }
        }
    
大致上就是這樣的狀態,可是還缺乏了次方、輸出等等,所以再加強:
        for(除數 = 2; 被除數 != 1; 除數加一){ // "!="是不等於的意思
            int 次方 = 0;
            while(被除數可以被除數整除){
                次方加一;
                被除數 = 被除數 / 除數;
            }

            if(次方 > 1){
                //要輸出含有"^"的結果
                print(除數 ^ 次方)
            }else if(次方 == 1){
                //僅輸出除數就好
                print(除數)
            }

            if(被除數 != 1 且 次方 != 0){
                //除數還未除盡 且 當次迴圈整除
                //就是肯定還有因數沒找完
                print(" * ")
            }
        }
    
因為題目說資料是大於1所以不用考慮被除數是1的情況。

程式碼如下:

/* a010:因數分解
*
* 2020/2/26
*
*/

import java.util.Scanner;

public class Pa010{
    public static void main(String [] args){
        Scanner scanner = new Scanner(System.in);

        while(scanner.hasNext()){
            int dividend = scanner.nextInt(); //dividend = 被除數

            for(int divisor = 2; dividend != 1; divisor++){ //divisor = 除數
                int pow = 0;
                while(dividend % divisor == 0){
                    pow++;
                    dividend /= divisor;		
                }
                if(pow > 1){
                    System.out.printf("%d^%d", divisor, pow);
                }else if(pow == 1){
                    System.out.print(divisor);
                }
                
                if(dividend != 1 && pow != 0){
                    System.out.print(" * ");
                }	
            }
            System.out.println();
        }
    }
}   

[zerojudge]a009. 解碼器

a009. 解碼器

這題是很經典的凱薩密碼,說穿了就是字的位移,舉例來說A這個字往後移兩格變成C,CAT就會變成ECV。
要解題首先要知道字元移位之後會變成哪個字元,幸好有個東西叫做ASCII碼,負責將數字對應到特定字元,例如小寫a是十進位的97。
又剛好英文字母表在ASCII中是有順序的排列的,也就是說a = 97, b = 98, c = 99......
所以將使用者輸入的字元轉換成數字之後就能夠簡單的進行移位。

那在Java中要如何把字元char轉換成整數int呢?用華麗的強制型態轉換就OK了!在char變數面前加上一個(int)就會變成整數,順帶一提Java中的字元是以Unicode(萬國碼)儲存的。
經過用眼睛觀察法發現,題目中的明文(原文)和密文(加密過後的暗號)之間差了7個字元,明文 - 7 = 密文

程式碼如下:

import java.util.Scanner;

public class Pa009{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);

        while(scanner.hasNext()){
            char[] line = scanner.nextLine().toCharArray(); //nextLine可以讀取一行,型態是String,String可以用toCharArray方法轉成字元陣列
            
            for(char ch: line){ //for-each,詳見https://openhome.cc/Gossip/JavaEssence/Foreach.html
                System.out.print((char)((int)ch - 7));
            }
            System.out.println();
        }
    }
}    
參考:http://mm.tlrc.mcu.edu.tw/courses/fhwang/accredit/JAVA/char.html

2020年2月4日 星期二

[zerojudge]a006. 一元二次方程式

a006. 一元二次方程式

求一元二次方程式 ax2+bx+c=0 的根

解題方案:
公式解讚!先算判別式 D = b2 - 4ac
D > 0: 兩相異根
D = 0: 重根
D < 0: 無解
在開根號之後要型態轉換成int,原本是double的但是題目很貼心只會出整數。
像這種題目Two different rootsasdfh2kq3ras.f.asd什麼的就不要用手打了,直接複製題目上面的說明,免得打錯。

程式碼如下:

import java.util.Scanner;

public class Pa006{
 public static void main(String[] args){
  Scanner scanner = new Scanner(System.in);

  while(scanner.hasNext()){
   int a = scanner.nextInt();
   int b = scanner.nextInt();
   int c = scanner.nextInt();

   int D = b * b - 4 * a * c;
   if (D > 0){
    System.out.printf("Two different roots x1=%d , x2=%d%n", ( -b + (int)Math.sqrt(D) ) / 2 / a, ( -b - (int)Math.sqrt(D) ) / 2 / a);
   }else if (D == 0){
    System.out.printf("Two same roots x=%d%n", -b / 2 / a);
   }else{
    System.out.println("No real root");
   }
  }
 }
}

怪貨Vim

Vim是一種文字編輯器(像Windows裡面的記事本),顧名思義是用來編輯文字的,他的前身是vi,在九〇年代就出生了,是上古時代的編輯器,有多種模式、快捷鍵組合,實在是一個很奇異又迷人的編輯器。

這樣說沒人知道他怪在哪裡,就舉點例子,首先游標移動並不需要用到方向鍵,取而代之的是在common-mode下按hjkl(下圖的遠古鍵盤中可以發現那時並沒有方向鍵)

遠古鍵盤

還有在common-mode中不能直接打字,而是要按i進入insert-mode中才可以輸入,「這樣太麻煩了吧!」似乎可以聽見大家的心聲,但是用久了就會很順手,玩起來可帥到不行~(不好意思我還沒達到那種境界)。

我學到現在大概懂了一些皮毛,會移動插入刪除複製,記事本大概已經沒用了:D,最後分享一下詳實介紹Vim的網頁:大家來學VIM(一個歷久彌新的編輯器)

gVim

[zerojudge]a004. 文文的求婚

a004. 文文的求婚

於是告訴文文說,如果你能在我回國之前回答我生日那年是不是閏年,則等她回國後就答應他的求婚。文文抓抓腦袋想不出來
文文抓抓腦袋發現不知道珊珊是幾年生:D
根據題目提示:西元年被4整除且不被100整除,或被400整除者即為閏年。想想要如何把這段文字變成程式

解題方案:

首先你要知道等於、不等於與且、或。

等於 ==
不等於 !=
&&
||
  • 用if/else
  • 用Conditional Operator(?:)

程式碼如下:

import java.util.Scanner;

public class Pa004{
 public static void main(String[] args){
  Scanner scanner = new Scanner(System.in);
  while(scanner.hasNext()){
   int input = scanner.nextInt();
   System.out.println( input % 4 == 0 && input % 100 != 0 || input % 400 == 0 ? "閏年": "平年" );
  }
 }
}

[zerojudge]a003. 兩光法師的占卜術

a003. 兩光法師的占卜術

(月*2+日)%3 = (月*2+日)/3的餘數,"%"是modulo簡稱mod,就是得該符號前除該符號後的餘
e.g. 5 mod 3 = 2

題外話:我發現Google搜尋可以用中文運算

解題關鍵:
記得%的優先序比較加減高所以要括號
Java的Operator Precedence

程式碼如下:

import java.util.Scanner;

public class Pa003{
 public static void main(String[] args){
  String[] fortune = {"普通", "吉", "大吉"};
  Scanner scanner = new Scanner(System.in);
  while(scanner.hasNext()){
   System.out.println(fortune[( scanner.nextInt() * 2 + scanner.nextInt() )% 3]);
  }
 }
}