2020年3月8日 星期日

[zerojudge]a147. Print it all

a147. Print it all

核心:i % 7 == 0? "": i + " "
如果i被7整除就輸出空字串,不整除就輸出i加空白。Yeah

BTW科皓不要

程式碼如下:

  1. /* Pa147.java
  2. * a147. Print it all
  3. *
  4. * 我的意思是說 科皓不要啦
  5. * 2020/3/8
  6. */
  7.  
  8. import java.util.Scanner;
  9.  
  10. public class Pa147{
  11.  
  12. public static void main(String[] args){
  13. Scanner scanner = new Scanner(System.in);
  14.  
  15. while(scanner.hasNext()){
  16. int n = scanner.nextInt();
  17.  
  18. for(int i = 1; i < n; i++){
  19. System.out.print(i % 7 == 0? "": i + " ");
  20. }
  21.  
  22. System.out.println();
  23. }
  24.  
  25. }
  26. }

[zerojudge]a121. 質數又來囉

a121. 質數又來囉

決定使用比較懶的方法,BigInteger再度出場,大材小用,牛刀割雞,把你用在這邊真是抱歉哈~

        if(big(元a)是質數) // 因為不管怎樣下面的迴圈都會執行一次,導致sum+1,所以如果a是質數的話要先-1,免得加兩次
            sum = -1
        else
            sum = 0
        
        while(big <= b){
            big = 下一個可能質數
            sum++
        }
    
很棒吧,只是單單輸出sum還不夠,因為不知道哪一筆資料會讓sum = -1,想破頭也想不出來什麼樣的情況會讓sum = -1,索性在sum == -1時輸出0
可能是真的有BUG吧,阿彌陀佛。

程式碼如下:

  1. /* Pa121.java
  2. * a121. 質數又來囉
  3. *
  4. * 科皓不要
  5. * 2020/3/8
  6. */
  7.  
  8. import java.util.Scanner;
  9. import java.math.BigInteger;
  10.  
  11. public class Pa121{
  12.  
  13. public static void main(String[] args){
  14. Scanner scanner = new Scanner(System.in);
  15.  
  16. while(scanner.hasNext()){
  17. BigInteger big = new BigInteger(scanner.next());
  18. BigInteger b = new BigInteger(scanner.next());
  19. int sum = big.isProbablePrime(1000)? 0: -1;
  20.  
  21. while(big.compareTo(b) != 1){
  22. big = big.nextProbablePrime();
  23. sum++;
  24. }
  25.  
  26. System.out.println(sum == -1? 0: sum);
  27. }
  28.  
  29. }
  30. }

[zerojudge]a104. 排序

a104. 排序

Arrays提供了sort(排序)方法,如果想要了解實作可以參考:演算法筆記Sort
Arrays還有toString,可以印出陣列,比方說{0, 1, 2, 3}的陣列會印成[0, 1, 2, 3],可是不需要逗號和中括號,所以用String本身就有的replaceAll方法, 用正規表示式(regular expression)去把[或]或,挑出來取代成空字串(殺掉)。
那個括號居然要兩個反斜線來表示,真是攪死我了。參考:Backslashes, escapes, and quoting

程式碼如下:

  1. /* Pa104.java
  2. * a104. 排序
  3. *
  4. * 科皓不要
  5. * 2020/3/8
  6. */
  7.  
  8. import java.util.Scanner;
  9. import java.util.Arrays;
  10.  
  11. public class Pa104{
  12.  
  13. public static void main(String[] args){
  14. Scanner scanner = new Scanner(System.in);
  15.  
  16. while(scanner.hasNext()){
  17. int[] nums = new int[scanner.nextInt()];
  18. for(int i = 0; i < nums.length; i++){
  19. nums[i] = scanner.nextInt();
  20. }
  21.  
  22. Arrays.sort(nums);
  23.  
  24. System.out.println(Arrays.toString(nums).replaceAll("[\\[\\],]", ""));
  25. }
  26.  
  27. }
  28. }

2020年3月7日 星期六

[zerojudge]a095. 麥哲倫的陰謀

a095. 麥哲倫的陰謀


因為黃色比較漂亮,絕對不是因為我畫錯了

  • 1個紅帽:
    1. 紅帽看到其他人都是黃帽→我就是紅帽,出去
    2. 黃帽發現紅帽走了→我不是紅帽,出去
  • 2個紅帽:
    1. 紅帽看到有一個紅帽,不能確定自己是不是紅帽
    2. 紅帽發現那個紅帽沒有走→那個紅帽看到有其他紅帽→那個紅帽就是我,出去
    3. 黃帽發現兩個紅帽都走了→我是黃帽,出去
  • 3個紅帽:
    1. 紅帽看到有兩個紅帽,不能確定自己是不是紅帽
    2. 紅帽發現那兩個紅帽都沒有走,不能確定自己是不是紅帽
    3. 紅帽發現那兩個紅帽都沒有走→我是紅帽,出去
    4. 黃帽發現三個紅帽都走了→我是黃帽,出去
  • 4個紅帽:
    1. 紅帽看到有三個紅帽,不能確定自己是不是紅帽
    2. 紅帽發現那三個紅帽都沒有走,不能確定自己是不是紅帽
    3. 紅帽發現那三個紅帽都沒有走,不能確定自己是不是紅帽
    4. 紅帽發現那三個紅帽都沒有走→我就是紅帽,出去
出去的前提是「完全確定自己是什麼顏色」,反過來說不出去是因為「不能確定自己是什麼顏色」。

完全不知道自己在講什麼,反正就是if(n == m) m天,else就m + 1天。

程式碼如下:

  1. /* Pa095.java
  2. * a095. 麥哲倫的陰謀
  3. *
  4. * 科皓不要
  5. * 2020/3/8
  6. */
  7.  
  8. import java.util.Scanner;
  9.  
  10. public class Pa095{
  11.  
  12. public static void main(String[] args){
  13. Scanner scanner = new Scanner(System.in);
  14.  
  15. while(scanner.hasNext()){
  16. int n = scanner.nextInt();
  17. int m = scanner.nextInt();
  18. System.out.println(n == m? m: m + 1);
  19. }
  20.  
  21. }
  22. }

[zerojudge]a065. 提款卡密碼

a065. 提款卡密碼

迴圈次數
很顯然你只要跑n-1次迴圈兩兩比對就可以了。
字元可以做運算,酷吧!

程式碼如下:

  1. /* Pa065.java
  2. * a065. 提款卡密碼
  3. *
  4. * 科皓不要
  5. * 2020/3/7
  6. */
  7.  
  8. import java.util.Scanner;
  9.  
  10. public class Pa065{
  11.  
  12. public static void main(String[] args){
  13. Scanner scanner = new Scanner(System.in);
  14.  
  15. while(scanner.hasNext()){
  16. char[] chs = scanner.next().toCharArray();
  17. for(int i = 0; i < chs.length - 1; i++){
  18. System.out.print(Math.abs(chs[i] - chs[i+1]));
  19. }
  20.  
  21. System.out.println();
  22. }
  23. }
  24. }

[zerojudge]a059. 完全平方和

a059. 完全平方和

在a~b之間尋找平方數然後加總,所以要找平方後>=a平方後<=b的兩個數當作起點和終點
開根號a之後可能是整數或小數,如果是小數就要「無條件進位」(ceiling),b則「無條件捨去」(floor)。
ceiling = 天花板
floor = 地板

程式碼如下:

  1. /* Pa059.java
  2. * a059. 完全平方和
  3. *
  4. * 科皓不要
  5. * 2020/3/7
  6. */
  7.  
  8. import java.util.Scanner;
  9.  
  10. public class Pa059{
  11.  
  12. public static void main(String[] args){
  13. Scanner scanner = new Scanner(System.in);
  14.  
  15. while(scanner.hasNext()){
  16.  
  17. int T = scanner.nextInt();
  18.  
  19. for(int i = 1; i <= T; i++){
  20. int sum = 0;
  21. int a = (int)Math.ceil(Math.sqrt(scanner.nextInt()));
  22. int b = (int)Math.floor(Math.sqrt(scanner.nextInt()));
  23.  
  24. for(; a <= b; a++){
  25. sum += a * a;
  26. }
  27.  
  28. System.out.println("Case " + i + ": " + sum);
  29. }
  30. }
  31. }
  32. }

[zerojudge]a058. MOD3

a058. MOD3

一臉就是要用陣列解的樣子,不用對不起它。因為%3, %3 + 1, %3 + 2是連續的嘛~

程式碼如下:

  1. /* a058. MOD3
  2. * Pa058.java
  3. *
  4. * 科皓不要
  5. * 2020/3/7
  6. */
  7.  
  8. import java.util.Scanner;
  9.  
  10. public class Pa058{
  11.  
  12. public static void main(String[] args){
  13. Scanner scanner = new Scanner(System.in);
  14.  
  15. while(scanner.hasNext()){
  16. int[] k = {0, 0, 0};
  17. int n = scanner.nextInt();
  18.  
  19. for(int i = 0; i < n; i++){
  20. k[scanner.nextInt() % 3]++;
  21. }
  22.  
  23. System.out.printf("%d %d %d%n", k[0], k[1], k[2]);
  24. }
  25. }
  26. }

[zerojudge]a054. 電話客服中心

a054. 電話客服中心

根據輸入提供的身分證後9碼,去列出符合規範的首位字母碼。
想到之前「a020. 身分證檢驗 」寫過的程式,複製貼上變成一個方法,檢查該身分證字號是否有效。
main裡面只要簡單的for迴圈讓A~Z跑過一遍,符合的列印出來就好,太輕鬆了吧!但是效率並沒有反向推算來的高喔,有興趣的可以試試看。

程式碼如下:

  1. /* a054. 電話客服中心
  2. *
  3. *
  4. * 2020/3/7
  5. */
  6.  
  7. import java.util.Scanner;
  8.  
  9. public class Pa054{
  10.  
  11. public static void main(String[] args){
  12. Scanner scanner = new Scanner(System.in);
  13.  
  14. while(scanner.hasNext()){
  15. String s = scanner.nextLine();
  16.  
  17. for(int i = 'A'; i <= 'Z'; i++){
  18. System.out.print(isValidid((char)i + s)? (char)i: "");
  19. }
  20.  
  21. System.out.println();
  22. }
  23. }
  24.  
  25. public static boolean isValidid(String input){
  26. String[] idNum = {"10", "11", "12", "13", "14", "15", "16", "17", "34",
  27. "18", "19", "20", "21", "22", "35", "23", "24", "25",
  28. "26", "27", "28", "29", "32", "30", "31", "33"};
  29.  
  30. int[] num = {1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1};
  31.  
  32. input = idNum[input.charAt(0) - 'A'] + input.substring(1);
  33.  
  34. int sum = 0;
  35.  
  36. for(int i = 0; i < input.length(); i++){
  37. sum += num[i] * Character.getNumericValue(input.charAt(i));
  38. }
  39.  
  40. return sum % 10 == 0;
  41. }
  42. }

2020年3月6日 星期五

[zerojudge]a053. Sagit's 計分程式

a053. Sagit's 計分程式

答對的題數越多單題得就越低,可以透過巢狀if、for迴圈、多重if之類的來達成,方法很多樣,我使用的是多重if,算式可以再進一步簡化。

想說一下關於&&和&的差別,&是只要一個是False就回傳False了,&&是即便第一個就是False,也會去執行判斷第二個項目。
如果判斷是這樣:a == b & a++ == c,那如果a != b 那 a 就不會+1了。若是寫成 a == b && a++ == c 那不論 a 是否等於 b ,到最後 a 都會+1

T F
T T F
F F F

程式碼如下:

  1. /* a053. Sagit's 計分程式
  2. *
  3. * 2020/3/7
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa053{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. int n = scanner.nextInt();
  15. int score = 0;
  16.  
  17. if(isBetween(0, n, 10)){
  18. score += n * 6;
  19. }else if(isBetween(11, n, 20)){
  20. score += 10 * 6;
  21. score += (n - 10) * 2;
  22. }else if(isBetween(21, n, 40)){
  23. score += 10 * 6;
  24. score += 10 * 2;
  25. score += (n - 20) * 1;
  26. }else{
  27. score = 100;
  28. }
  29.  
  30. System.out.println(score);
  31. }
  32. }
  33.  
  34. public static boolean isBetween(int min, int v, int max){
  35. return min <= v & v <= max;
  36. }
  37. }

2020年3月5日 星期四

[zerojudge]a044. 空間切割

a044. 空間切割

圖1 圖2
參考影片:(DM10-20131118-03) 平面分割空間

沒有用lineCut和spaceCut是因為會超時TLE(Time Limit Exceed)

程式碼如下:

  1. /* a044. 空間切割
  2. *
  3. * 2020/3/5
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa044{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. System.out.println(spaceCutSuper(scanner.nextInt()));
  15. }
  16. }
  17.  
  18. public static int lineCut(int n){
  19. return n == 0? 1: lineCut(n - 1) + n;
  20. }
  21.  
  22. public static int spaceCut(int n){
  23. return n == 0? 1: spaceCut(n - 1) + lineCut(n - 1);
  24. }
  25.  
  26. public static int spaceCutSuper(int n){
  27. return (n * n * n + 5 * n + 6 ) / 6;
  28. }
  29. }

2020年3月4日 星期三

[zerojudge]a042. 平面圓形切割

a042. 平面圓形切割

平面圓形切割

    a0 = 1
    a1 = 2
    a2 = 4
    a3 = 8
    a4 = 14
    a5 = 22
    
an - an-1 = 2 * (n - 1), if n > 1
=> an = 2 * (n - 1) + an-1

寫成遞迴就OK了,也可以寫成公式
推導
an = n2 - n + 2, if n > 0

程式碼如下:

  1. /* a042. 平面圓形切割
  2. *
  3. * 2020/3/3
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa042{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. System.out.println(circleCut(scanner.nextInt()));
  15. }
  16. }
  17.  
  18. public static int circleCut(int n){
  19. return n == 1? 2: 2 * (n - 1) + circleCut(n - 1);
  20. }
  21.  
  22. }

2020年3月2日 星期一

[zerojudge]a040. 阿姆斯壯數

a040. 阿姆斯壯數

阿姆斯壯數有好多名字,我聽過的是水仙花數
其特徵就是長度n位的數,各位數的n次方總和等於自身,例如115 = 1^3 + 1^3 + 5^3

解題想法:
寫一個方法(method)來判斷一數是否為水仙花數,是回傳true,不是就回傳false。
方法內容是先將整數換成字串再換成字元陣列方便對各位數計算,for迴圈之中使用之前用過得Character.getNumericValue。

程式碼如下:

  1. /* a040. 阿姆斯壯數
  2. *
  3. * 2020/3/2
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa040{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. int n = scanner.nextInt();
  15. int m = scanner.nextInt();
  16.  
  17. boolean none = true;
  18.  
  19. for(; n <= m; n++){
  20. if(isNarcissistic(n)){
  21. System.out.print(n + " ");
  22. none = false;
  23. }
  24. }
  25.  
  26. System.out.println(none? "none": "");
  27. }
  28. }
  29.  
  30. public static boolean isNarcissistic(int num){
  31. char[] nums = Integer.toString(num).toCharArray();
  32.  
  33. int sum = 0;
  34.  
  35. for(char ch: nums){
  36. sum += (int)Math.pow(Character.getNumericValue(ch), nums.length);
  37. }
  38.  
  39. return num == sum;
  40. }
  41. }

[zerojudge]a038. 數字翻轉

a038. 數字翻轉

1234 → 4321,1000 → 0001 → 1,000 → 0。
之前迴文用過的StringBuffer加上Integer.parseInt()就完成了。

程式碼如下:

  1. /* a038. 數字翻轉
  2. *
  3. * 2020/3/2
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa038{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. StringBuffer sb = new StringBuffer(scanner.next());
  15.  
  16. System.out.println(Integer.parseInt(sb.reverse().toString()));
  17. }
  18. }
  19. }

2020年3月1日 星期日

[zerojudge]a034. 二進位制轉換

a034. 二進位制轉換

日常生活中使用的是十進位,遇到十就進位,那二進位就是遇到二就進位。 十進位轉二進位 可以參考:【CodingBar】什麼是二進位?|程人式界科普 #01

方法一—直接toBinaryString,超簡單暴力。
方法二—樸實除除樂,如上圖去取除二之後的餘數,然後把順序倒過來輸出。

方法一:

  1. /* a034. 二進位制轉換
  2. *
  3. * 2020/3/2
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa034{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. System.out.println(Integer.toBinaryString(scanner.nextInt()));
  15. }
  16. }
  17. }

方法二:

  1. /* a034. 二進位制轉換
  2. *
  3. * 2020/3/2
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa034_2{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. int decNum = scanner.nextInt();
  15.  
  16. boolean[] binNum = new boolean[(int)(Math.log(decNum) / Math.log(2)) + 1];
  17.  
  18. for(int i = binNum.length - 1; i >= 0; i--){
  19. binNum[i] = decNum % 2 == 0? false: true;
  20. decNum /= 2;
  21. }
  22.  
  23. for(int i = 0; i < binNum.length; i++){
  24. System.out.print(binNum[i]? 1: 0);
  25. }
  26.  
  27. System.out.println();
  28. }
  29. }
  30. }

[zerojudge]a024. 最大公因數(GCD)

a024. 最大公因數(GCD)

我作弊,用BigInteger.gcd(),缺點是比較慢。
另一個方法是輾轉相除法,非常經典的遞迴,可以看看這個影片:歐幾里得演算法(輾轉相除法)

        輾轉相除法:
        public static int gcd(int a, int b){
            return b == 0 ? a: gcd(b, a % b);
        }
    

程式碼如下:

  1. /* a024. 最大公因數(GCD)
  2. *
  3. * 2020/3/2
  4. */
  5.  
  6. import java.util.Scanner;
  7. import java.math.BigInteger;
  8.  
  9. public class Pa024{
  10.  
  11. public static void main(String[] args){
  12. Scanner scanner = new Scanner(System.in);
  13.  
  14. while(scanner.hasNext()){
  15. BigInteger big_a = new BigInteger(scanner.next());
  16. BigInteger big_b = new BigInteger(scanner.next());
  17. System.out.println(big_a.gcd(big_b));
  18. }
  19. }
  20. }

[zerojudge]a022. 迴文

a022. 迴文

正向和反向讀起來一樣就是迴文,例如說:上海自來水來自海上,用迴圈不就好了嗎?不好意思我太懶了,馬上查查有沒有把String倒過來的方法,發現用StringBuffer(和String很像的類別)可以做到,兩行解決!

        迴圈解:
        boolean isPalindrome = true;

        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) != s.charAt(s.length() - 1 - i)){
                isPalindrome = false;
            }
        }

        print(isPalindrome? "yes": "no");
    

程式碼如下:

  1. /* a022. 迴文
  2. *
  3. * 2020/3/2
  4. */
  5.  
  6. import java.util.Scanner;
  7.  
  8. public class Pa022{
  9. public static void main(String[] args){
  10. Scanner scanner = new Scanner(System.in);
  11.  
  12. while(scanner.hasNext()){
  13. StringBuffer sb = new StringBuffer(scanner.next());
  14.  
  15. System.out.println(sb.toString().equals(sb.reverse().toString())? "yes": "no");
  16. }
  17. }
  18. }

[zerojudge]a021. 大數運算

a021. 大數運算

理論上大數運算是很驚悚的問題,因為就算是long long int也不夠儲存,所以要把每個位數存進陣列然後透過超複雜的演算法才能得到答案。 幸好Java有幫我們寫好了函式庫可用,那就是BigInteger這個神奇類別,提供很多大數的計算方法,輕輕鬆鬆解決這個地獄難題。

如果對大數運算的實作有興趣的話可以看這個演算法筆記,裡面詳盡介紹了如何用優雅至極的語法完成大數運算。

程式碼如下:

  1. /* a021. 大數運算
  2. *
  3. * 2020/3/2
  4. */
  5.  
  6. import java.util.Scanner;
  7. import java.math.BigInteger;
  8.  
  9. public class Pa021{
  10.  
  11. public static void main(String[] args){
  12. Scanner scanner = new Scanner(System.in);
  13.  
  14. while(scanner.hasNext()){
  15. BigInteger big_a = new BigInteger(scanner.next());
  16. String op = scanner.next();
  17. BigInteger big_b = new BigInteger(scanner.next());
  18. switch(op){
  19. case "+":
  20. big_a = big_a.add(big_b);
  21. break;
  22. case "-":
  23. big_a = big_a.add(big_b.negate());
  24. break;
  25. case "*":
  26. big_a = big_a.multiply(big_b);
  27. break;
  28. case "/":
  29. big_a = big_a.divide(big_b);
  30. break;
  31. }
  32.  
  33. System.out.println(big_a);
  34. }
  35. }
  36. }

[zerojudge]a020. 身分證檢驗

a020. 身分證檢驗

請先閱讀:身分證驗證規則

英文代號看似連續,結果參雜一些例外,只好依照英文字母的順序打成字串陣列:( 然後用整數陣列儲存每個編號要乘上的值。
值得提的點應該是Character.getNumericValue(),可以把字元換算成unicode的編碼。

題外話:A123456789是真有其人,被別人盜用的頻率超高,三天兩頭就要跑一次法院,但是這位勇者不換號碼,因為很麻煩。

程式碼如下:

  1. /* a020. 身份證檢驗
  2. *
  3. *
  4. * 2020/3/1
  5. */
  6.  
  7. import java.util.Scanner;
  8.  
  9. public class Pa020{
  10.  
  11. public static void main(String[] args){
  12. Scanner scanner = new Scanner(System.in);
  13.  
  14. String[] idNum = {"10", "11", "12", "13", "14", "15", "16", "17", "34",
  15. "18", "19", "20", "21", "22", "35", "23", "24", "25",
  16. "26", "27", "28", "29", "32", "30", "31", "33"};
  17.  
  18. int[] num = {1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1};
  19.  
  20. while(scanner.hasNext()){
  21. String input = scanner.nextLine();
  22. input = idNum[Character.getNumericValue(input.charAt(0)) - Character.getNumericValue('A')] + input.substring(1);
  23.  
  24. int sum = 0;
  25.  
  26. for(int i = 0; i < input.length(); i++){
  27. sum += num[i] * Character.getNumericValue(input.charAt(i));
  28. }
  29.  
  30. System.out.println(sum % 10 == 0 ? "real": "fake");
  31. }
  32. }
  33. }

[zerojudge]a017. 五則運算

a017. 五則運算

先乘除後加減、括號優先程式是怎麼寫的?!不知道你小時後有沒有想過這種問題,至少我是沒有啦:D

做這題要先了解堆疊,對堆疊(Stack)這種資料結構不熟的話可以看看【Ken將】電腦課小教室 - Class.Null - 堆疊與佇列 ,再來了解運算式的前序、中序、後序表示法資料結構教學 : Infix 轉 Postfix
手稿

手稿

程式碼如下:

  1. /*a017. 五則運算
  2. *
  3. * 2020/2/28
  4. */
  5. import java.util.Scanner;
  6. import java.util.Stack;
  7.  
  8. public class Pa017{
  9.  
  10. public static void main(String[] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. System.out.println(evaluate(scanner.nextLine()));
  15. }
  16. }
  17.  
  18. public static int evaluate(String s){
  19. String[] exp = s.split(" ");
  20.  
  21. Stack ops = new Stack();
  22. Stack vals = new Stack();
  23. for(String token: exp){
  24. if("(".equals(token)){
  25. ops.push(token);
  26. }else if(")".equals(token)){
  27. // 不斷計算直到遇到右括號
  28. while(!"(".equals(ops.peek())){
  29. vals.push(calc(vals.pop(), ops.pop(), vals.pop()));
  30. }
  31. // 把遇到的右括號pop掉
  32. ops.pop();
  33. }else if("+-*/%".contains(token)){
  34. // 如果ops還有運算子 且 ops最頂層運算子的優先順序 >= token運算子的優先順序
  35. while(!ops.isEmpty() && priority(ops.peek()) >= priority(token)){
  36. vals.push(calc(vals.pop(), ops.pop(), vals.pop()));
  37. }
  38. ops.push(token);
  39. }else{
  40. vals.push(Integer.parseInt(token));
  41. }
  42. }
  43. while(!ops.isEmpty()){
  44. vals.push(calc(vals.pop(), ops.pop(), vals.pop()));
  45. }
  46. return vals.pop();
  47. }
  48. public static int priority(String op){
  49. return "*/%".contains(op) ? 2 : "+-".contains(op) ? 1 : 0;
  50. }
  51. // ab位置對調
  52. public static int calc(int b, String operator, int a){
  53. switch(operator){
  54. case "+": return a + b;
  55. case "-": return a - b;
  56. case "*": return a * b;
  57. case "/": return a / b;
  58. case "%": return a % b;
  59. default:
  60. System.out.println("unknown operator");
  61. return 0;
  62. }
  63. }
  64. }

2020年2月27日 星期四

[zerojudge]a015. 矩陣的翻轉

a015. 矩陣的翻轉

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

程式碼如下:

  1. /* a015:矩陣的翻轉
  2. *
  3. * 2020/2/27
  4. *
  5. */
  6.  
  7. import java.util.Scanner;
  8.  
  9. public class Pa015{
  10.  
  11. public static void main(String [] args){
  12. Scanner scanner = new Scanner(System.in);
  13.  
  14. while(scanner.hasNext()){
  15. int row = scanner.nextInt();
  16. int col = scanner.nextInt();
  17.  
  18. int[][] matrix = new int[col][row];
  19.  
  20. for(int i = 0; i < row; i++){
  21. for(int j = 0; j < col; j++){
  22. matrix[j][i] = scanner.nextInt();
  23. }
  24. }
  25.  
  26. for(int i = 0; i < col; i++){
  27. for(int j = 0; j < row; j++){
  28. System.out.print(matrix[i][j] + " ");
  29. }
  30. System.out.println();
  31. }
  32.  
  33. }
  34. }
  35.  
  36. }

[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)…以此類推。

程式碼如下:

  1. /* a013:羅馬數字
  2. *
  3. * 2020/2/27
  4. *
  5. */
  6.  
  7. import java.util.Scanner;
  8.  
  9. public class Pa013{
  10.  
  11. static String roman = "IVXLCDM";
  12. static int[] num = {1, 5, 10, 50, 100, 500, 1000};
  13.  
  14. public static void main(String [] args){
  15. Scanner scanner = new Scanner(System.in);
  16.  
  17. while(scanner.hasNext()){
  18. String word = scanner.next();
  19. if(word.equals("#")) return;
  20. int a = romanToInt(word);
  21. int b = romanToInt(scanner.next());
  22. System.out.println(intToRoman(Math.abs(a - b)));
  23. }
  24. }
  25.  
  26. public static int romanToInt(String s){
  27. s += "I";
  28. int result = 0;
  29.  
  30. for(int i = 1; i < s.length(); i++){
  31. int current = num[roman.indexOf(s.charAt(i - 1))];
  32. int next = num[roman.indexOf(s.charAt(i))];
  33.  
  34. if(current >= next){
  35. result += current;
  36. }else{
  37. i++;
  38. result += next - current;
  39. }
  40. }
  41. return result;
  42. }
  43.  
  44. public static String intToRoman(int val){
  45. if(val == 0) return "ZERO";
  46.  
  47. int[] nums = new int[(int)Math.log10(val) + 1];
  48. String result = "";
  49.  
  50. for(int i = 0; i < nums.length; i++){
  51. nums[i] = val % 10;
  52. val /= 10;
  53. }
  54.  
  55. for(int i = nums.length - 1; i >= 0; i--){
  56. if(nums[i] == 9){
  57. result += roman.charAt(i * 2);
  58. result += roman.charAt(i * 2 + 2);
  59. }else if(nums[i] >= 5){
  60. result += roman.charAt(i * 2 + 1);
  61. for(int j = 0; j < nums[i] - 5; j++){
  62. result += roman.charAt(i * 2);
  63. }
  64. }else if(nums[i] == 4){
  65. result += roman.charAt(i * 2);
  66. result += roman.charAt(i * 2 + 1);
  67. }else{
  68. for(int j = 0; j < nums[i]; j++){
  69. result += roman.charAt(i * 2);
  70. }
  71. }
  72. }
  73.  
  74. return result;
  75. }
  76. }

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的情況。

程式碼如下:

  1. /* a010:因數分解
  2. *
  3. * 2020/2/26
  4. *
  5. */
  6.  
  7. import java.util.Scanner;
  8.  
  9. public class Pa010{
  10. public static void main(String [] args){
  11. Scanner scanner = new Scanner(System.in);
  12.  
  13. while(scanner.hasNext()){
  14. int dividend = scanner.nextInt(); //dividend = 被除數
  15.  
  16. for(int divisor = 2; dividend != 1; divisor++){ //divisor = 除數
  17. int pow = 0;
  18. while(dividend % divisor == 0){
  19. pow++;
  20. dividend /= divisor;
  21. }
  22. if(pow > 1){
  23. System.out.printf("%d^%d", divisor, pow);
  24. }else if(pow == 1){
  25. System.out.print(divisor);
  26. }
  27. if(dividend != 1 && pow != 0){
  28. System.out.print(" * ");
  29. }
  30. }
  31. System.out.println();
  32. }
  33. }
  34. }

[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 = 密文

程式碼如下:

  1. import java.util.Scanner;
  2.  
  3. public class Pa009{
  4. public static void main(String[] args){
  5. Scanner scanner = new Scanner(System.in);
  6.  
  7. while(scanner.hasNext()){
  8. char[] line = scanner.nextLine().toCharArray(); //nextLine可以讀取一行,型態是String,String可以用toCharArray方法轉成字元陣列
  9. for(char ch: line){ //for-each,詳見https://openhome.cc/Gossip/JavaEssence/Foreach.html
  10. System.out.print((char)((int)ch - 7));
  11. }
  12. System.out.println();
  13. }
  14. }
  15. }
參考: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什麼的就不要用手打了,直接複製題目上面的說明,免得打錯。

程式碼如下:

  1. import java.util.Scanner;
  2.  
  3. public class Pa006{
  4. public static void main(String[] args){
  5. Scanner scanner = new Scanner(System.in);
  6.  
  7. while(scanner.hasNext()){
  8. int a = scanner.nextInt();
  9. int b = scanner.nextInt();
  10. int c = scanner.nextInt();
  11.  
  12. int D = b * b - 4 * a * c;
  13. if (D > 0){
  14. 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);
  15. }else if (D == 0){
  16. System.out.printf("Two same roots x=%d%n", -b / 2 / a);
  17. }else{
  18. System.out.println("No real root");
  19. }
  20. }
  21. }
  22. }

怪貨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(?:)

程式碼如下:

  1. import java.util.Scanner;
  2.  
  3. public class Pa004{
  4. public static void main(String[] args){
  5. Scanner scanner = new Scanner(System.in);
  6. while(scanner.hasNext()){
  7. int input = scanner.nextInt();
  8. System.out.println( input % 4 == 0 && input % 100 != 0 || input % 400 == 0 ? "閏年": "平年" );
  9. }
  10. }
  11. }

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

a003. 兩光法師的占卜術

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

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

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

程式碼如下:

  1. import java.util.Scanner;
  2.  
  3. public class Pa003{
  4. public static void main(String[] args){
  5. String[] fortune = {"普通", "吉", "大吉"};
  6. Scanner scanner = new Scanner(System.in);
  7. while(scanner.hasNext()){
  8. System.out.println(fortune[( scanner.nextInt() * 2 + scanner.nextInt() )% 3]);
  9. }
  10. }
  11. }

2020年1月31日 星期五

[zerojudge]a002. 簡易加法

a002. 簡易加法

你有沒有想過,有一天,a和b的和會等於a+b?不可能,如果我這樣想那我是傻子,我沒有那麼笨。

解題關鍵:
把兩個數字加起來,把兩個nextInt()放在一起輸出,很簡單吧

程式碼如下:

  1. import java.util.Scanner;
  2.  
  3. public class Pa001{
  4. public static void main(String[] args){
  5. Scanner scanner = new Scanner(System.in);
  6. while(scanner.hasNext()){
  7. System.out.print(scanner.nextInt() + scanner.nextInt());
  8. }
  9. }
  10. }

[zerojudge]a001. 哈囉

a001. 哈囉

印出"hello, "加上使用者所輸入的字串就是這麼簡單

可是我覺得可以來個a000. HelloWorld,單單就印出"Hello World!"就好,記得我以前是用C++寫,因為資料有很多筆而卡關,那時候連原因都不知道。

話說回來Hello World是誰想出來的?我好奇查了一下發現是Brian Kernighan老大寫的。真是一個佳話,害我看到HELLO WORLD的時候興奮了一下

HELLO WORLD宣傳圖
你好喔

程式碼如下:

  1. import java.util.Scanner;
  2.  
  3. public class Pa001{
  4. public static void main(String[] args){
  5. Scanner scanner = new Scanner(System.in);
  6. while(scanner.hasNext()){
  7. System.out.printf("hello, %s", scanner.next());
  8. }
  9. }
  10. }