CSC1003 A2 T3 Ascii Art

A2 T3 Ascii Art

Tutorial by George (Wechat ID: Geo1123rge).

Keep it private before the assignment ends.

这里用哈希做法。

读入字符模板

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner S = new Scanner(System.in);
        int[] record = new int[26]; // 每个大字母的哈希值
        for (int i = 0; i < 26; ++i) {
            String[] s = new String[7]; // 所有大字母高度都是 7
            int[] len = new int[7]; // 这里不必要,但是因为 String 类的 .length() 复杂度是 O(length) 的,所以存一下快一点。还有另外一个作用就是辅助后面删除字符串尾空格
            int mx = 0; // 一定要求出字母每行的最大宽度,因为单个字母的最大宽度就是它在单词里的宽度
            for (int j = 0; j < 7; ++j) {
                s[j] = S.nextLine();
                while (s[j].length() < 2) s[j] = S.nextLine(); // 丢弃空行
                len[j] = s[j].length();
                while (len[j] > 0 && s[j].charAt(len[j] - 1) != '#') --len[j]; // 注意这很重要,字符串尾可能会有空格
                if (len[j] > mx) mx = len[j];
            }
            int mod = 998244353; // 哈希模数,具体作用看后面
            int sum = 0;
            for (int j = 0; j < 7; ++j) for (int k = 0; k < mx; ++k) { // 对整个 7 * mx 的方阵哈希
                sum = sum * 2 % mod;
                if (k < len[j] && s[j].charAt(k) == '#') sum = (sum + 1) % mod;
            }
            // 仔细观察上面两行,如果不看 % mod 且 sum 不会爆 int,那么求出来的 sum 就是把大字母矩阵 7 行接在一起后的二进制数。但是这个数太大,所以对 998244353 取模——我们发现所有相同字母这样计算后的值(可称为哈希值)都是一样的,而不同字母都是不一样的(这是个巧合,但是每个字母有 998244353 种哈希值的可能取值,所以出现相同的概率真的很小,而这里的概率就是 0,对比输出的 record[i] 即可知)
            // System.out.println((char)(i + 'A') + ": " + sum);
            // for (int j = 0; j < 7; ++j) System.out.print(len[j] + " ");
            // System.out.println();
            record[i] = sum;
        }
        for (int i = 0; i < 26; ++i) System.out.print(record[i] + ", ");
        System.out.println();
    }
}

输出结果:

557138, 783037474, 253713189, 246166578, 57958169, 57958106, 247060227, 838444457, 258369135, 355913267, 302150034, 8613417, 592770654, 528807205, 512275521, 782249380, 518568510, 785398183, 132274982, 567184348, 167355700, 117667438, 565824435, 495066258, 206529121, 921117289, 

解题代码

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner S = new Scanner(System.in);
        int[] h = {557138, 783037474, 253713189, 246166578, 57958169, 57958106, 247060227, 838444457, 258369135, 355913267, 302150034, 8613417, 592770654, 528807205, 512275521, 782249380, 518568510, 785398183, 132274982, 567184348, 167355700, 117667438, 565824435, 495066258, 206529121, 921117289}; // 把上题的输出存成数组,h[i] 是第 i 个大字母的哈希值(A - h[0], B - h[1], etc.)
        // about how h[] is created, look at H
        int n = S.nextInt();
        while (n-- > 0) {
            String[] s = new String[7];
            int[] len = new int[7];
            int mx = 0;
            for (int j = 0; j < 7; ++j) {
                s[j] = S.nextLine();
                while (s[j].length() < 2) s[j] = S.nextLine();
                len[j] = s[j].length();
                while (len[j] > 0 && s[j].charAt(len[j] - 1) != '#') --len[j];
                if (len[j] > mx) mx = len[j];
            } // 读入一个单词的字符串数组同前一份代码
            int mod = 998244353;
            int last = 0; // 见下,记录上一个字母分隔后的下一列
            String res = "";
            for (int k = 0; k < mx; ++k) {
                boolean empty = true;
                for (int j = 0; j < 7; ++j) if (k < len[j] && s[j].charAt(k) == '#') {
                    empty = false;
                    break;
                } 
                // empty 表示列 k 是否为空,如果是空的,表示这里有一个字母分隔
                if (empty) {
                    int sum = 0;
                    for (int j = 0; j < 7; ++j) for (int p = last; p < k; ++p) {
                        sum = sum * 2 % mod;
                        if (p < len[j] && s[j].charAt(p) == '#') sum = (sum + 1) % mod;
                    } // 同前一份代码,把两个空列间的大字母矩阵展开哈希
                    for (int x = 0; x < 26; ++x) if (h[x] == sum) { // 判断是不是字母 (char)(x + 'A')
                        res += (char)(x + 'A');
                        break;
                    }
                    last = k + 1; // 记录上一个字母分隔后的下一列
                }
            }
			// 下面:别忘了最后一个空列之后虽然已没有空列,但是还有一个大字母矩阵,所以还要展开哈希
            int sum = 0;
            for (int j = 0; j < 7; ++j) for (int p = last; p < mx; ++p) {
                sum = sum * 2 % mod;
                if (p < len[j] && s[j].charAt(p) == '#') sum = (sum + 1) % mod;
            }
            for (int x = 0; x < 26; ++x) if (h[x] == sum) {
                res += (char)(x + 'A');
                break;
            } // 同上
            System.out.println(res);
        }
    }
}

题目至此解决。哈希的好处不关是可以减少代码长度,也可以让我们对复杂的字母矩阵获得更直观的把握。在复杂的代码中一份代码读入简单的东西然后代码进行几番复杂的计算之后可能又得到一个简单的值,这个时候假如能在某个地方将代码打断,将前半部分的成果总结为几个简单,甚至固定的数据,就再好不过了,能大大减少代码的复杂度,增加代码的正确性。

posted @   Pizza1123  阅读(132)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
主题色彩