一道加密解密笔试题

题目原文如下,对方可能还在用这道题,所以具体实现就不给了。[2014/04/30]估摸着此题已无时效,附上实现代码。


有一种常见但不安全的加密文本的方法, 是将字母表中的某个字母固定地取代另一个字母.


为了保证加密是可逆的, 没有两个字母会被同一个字母取代.

你的任务是要解密几行文本. 这几行文本在被加密的时候可能每一行都使用了不同的取代方案, 而且所有的单词都来自一个已知的词典.


输入:

输入文件包含多行. 第一行是一个整数n, 表示词典中单词的数量.
第二行开始是n个单词, 每行一个单词.
解密后的明文中的所有单词都是由这些单词组成的.
在单词之后, 是若干行密文. 每一行都是按上述方式加密的.

词典的大小小于1000. 单词不超过16个字母.
加密前后的字母都只有小写. 每一行不超过80字母.

输出:

解密每一行密文, 并打印明文. 如果有多种可能的明文, 输出任何一个即可.
如果没有可能的明文, 用星号来取代每一个字母.

测试用例1:
输入:
5
the
big
bang
theory
rock
xej mck mfok xejpwz wpdu
fff jjj pppp dddddd

输出:
the big bang theory rock
*** *** **** ******

测试用例2:
输入:
23
already
diplomacy
senate
house
agreed
hardening
further
representatives
delay
to
passed
has
iran
but
chance
succeed
a
sanctions
of
bill
allow
action
the
rko kzxbo zt sonsobohrvrqaob kvb vpsovud nvbbou v wqpp kvsuohqhi qsvh bvhgrqzhb wxr rko bohvro visoou rz uopvd txsrkos vgrqzh rz vppzy uqnpzcvgd v gkvhgo rz bxggoou

输出:
the house of representatives has already passed a bill hardening iran sanctions but the senate agreed to delay further action to allow diplomacy a chance to succeed

测试用例3:
输入:
145
diplomacy
agreed
move
sources
committee
talks
yet
impact
alarmist
republican
should
to
only
willing
pretty
details
has
over
arguments
them
his
get
know
got
iranians
aggressively
bring
iranian
michael
wednesday
banking
trita
kerrys
further
security
soft
round
hardening
senate
house
national
idea
likely
are
our
really
said
for
robert
representatives
seriously
new
told
we
iran
ability
pressure
succeed
although
by
on
of
could
wrong
foreign
american
action
senator
argue
whole
thats
already
tough
dont
crapo
president
table
aback
toomey
top
legislation
relations
next
kahl
their
program
passed
taken
white
was
is
listen
kerry
way
geneva
that
menendez
but
forward
line
he
east
sanctions
bill
colin
believes
will
limit
were
more
agree
and
sincere
middle
warning
at
council
in
parsi
negotiations
pat
goal
shelby
delay
how
chairman
afp
congress
warnings
center
director
chance
rouhanis
negotiating
end
meaningful
warming
a
richard
cover
maintain
allow
position
the
sounded
jrg rxavg xi ogwogvgnjfjbcgv rfv ftogflp wfvvgl f ubtt rfolgnbny bofn vfndjbxnv uaj jrg vgnfjg fyoggl jx lgtfp iaojrgo fdjbxn jx fttxk lbwtxhfdp f drfndg jx vaddggl

zgoop bv tbzgtp jx foyag ixo f iaojrgo lgtfp jx dxcgo jrg ngej oxanl xi jftzv vxaodgv vfbl

uaj vgnfjg ixogbyn ogtfjbxnv dxhhbjjgg drfbohfn oxugoj hgngnlgq vxanlgl jfzgn fufdz up jrg krbjg rxavg kfonbny

jrfjv wogjjp ftfohbvj xcgo jrg jxw rg jxtl fiw

ogwautbdfn vgnfjxo obdrfol vrgtup vfbl jrfj jrg krbjg rxavg kfonbnyv xcgo jrg bhwfdj xi ngk vfndjbxnv kgog koxny

kg lxnj znxk rxk vbndgog pgj jrg bofnbfnv fog bn xao krxtg ngyxjbfjbxnv rg vfbl

vgnfjxo hbdrfgt dofwx jrg jxw ogwautbdfn xn jrg ufnzbny dxhhbjjgg jxtl fiw rg ugtbgcgv jrg vgnfjg vrxatl hxcg fyyogvvbcgtp ixokfol xn xao vfndjbxnv tgybvtfjbxn ftjrxayr rg vfbl rg kfv kbttbny jx tbvjgn jx zgoopv foyahgnjv kglngvlfp fnl rbv lgjfbtv xn jrg ygngcf ngyxjbfjbxnv

ogwautbdfn vgnfjxo wfj jxxhgp jxtl fiw jrfj ogfttp jxayr vfndjbxnv kgog jrg xntp kfp jx uobny bofn jx jrg jfutg bn f hgfnbnyiat kfp fnl ygj jrgh jx fyogg jx gnl jrgbo woxyofh

dxtbn zfrt lbogdjxo xi jrg hblltg gfvj vgdaobjp woxyofh fj jrg dgnjgo ixo f ngk fhgobdfn vgdaobjp vfbl dxnyogvv kfv kfohbny jx jrg blgf jrfj vfndjbxnv wogvvaog yxj bofn jx jrg ngyxjbfjbny jfutg fnl hxog wogvvaog kbtt ygj jrgh xcgo jrg yxft tbng

uaj jobjf wfovb wogvblgnj xi jrg nfjbxnft bofnbfn fhgobdfn dxandbt vfbl ngk vfndjbxnv dxatl vgobxavtp tbhbj oxarfnbv fubtbjp jx hfbnjfbn rbv vxij wxvbjbxn xn jrg ngyxjbfjbxnv

输出:
the house of representatives has already passed a bill hardening iran sanctions but the senate agreed to delay further action to allow diplomacy a chance to succeed

kerry is likely to argue for a further delay to cover the next round of talks sources said

but senate foreign relations committee chairman robert menendez sounded taken aback by the white house warning

thats pretty alarmist over the top he told afp

republican senator richard shelby said that the white house warnings over the impact of new sanctions were wrong

we dont know how sincere yet the iranians are in our whole negotiations he said

senator michael crapo the top republican on the banking committee told afp he believes the senate should move aggressively forward on our sanctions legislation although he said he was willing to listen to kerrys arguments wednesday and his details on the geneva negotiations

republican senator pat toomey told afp that really tough sanctions were the only way to bring iran to the table in a meaningful way and get them to agree to end their program

colin kahl director of the middle east security program at the center for a new american security said congress was warming to the idea that sanctions pressure got iran to the negotiating table and more pressure will get them over the goal line

but trita parsi president of the national iranian american council said new sanctions could seriously limit rouhanis ability to maintain his soft position on the negotiations



实现如下,注释不全,敬请见谅:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.*;

public class Decoder {

    // 密码表,26个英文字母的映射关系
    HashMap<Character, Character> decodingKey = null;

    // 明文表,Key值表示明文单词长度,意在将同一长度的明文放在同一个列表中;Value值表示同一长度的明文列表
    HashMap<Integer, ArrayList<String>> dict = new HashMap<Integer, ArrayList<String>>();

    // 密文表,Key值表示密文;Value值表示将要匹配的在同一长度的明文列表中的明文索引,从0开始
    HashMap<String, Integer> encoded = null;

    public void println(String line) {
        for (Character c : line.toCharArray()) {
            if (c == ' ') {
                System.out.print(c);
                continue;
            }

            if (decodingKey == null)
                System.out.print('*');
            else
                System.out.print(decodingKey.get(c));
        }
        System.out.println();
    }

    public void decoding(String filename) throws Exception {        
        FileInputStream file = new FileInputStream(filename);
        BufferedReader fd = new BufferedReader(new InputStreamReader(file));

        // 读取明文字典大小
        String line =  fd.readLine();
        int value = Integer.valueOf(line);

        // 保存字典
        for (int i = 0; i < value; i++) {
            line = fd.readLine().trim(); // 删除空白字符
            ArrayList<String> array = dict.get(line.length());
            if (array == null)
                array = new ArrayList<String>();
            array.add(line);
            dict.put(line.length(), array);
        }

        // 处理每一行密文,并打印
        line = fd.readLine();
        while(line != null) {
            if (line.trim().equals("")) {
                System.out.println();
            }
            else {
                String array[] = line.split("\\s+"); // [\\t\\n \\f\\r]+
                if (array.length != 0) {
                    encoded = new HashMap<String, Integer>();
                    for (String s : array)
                        encoded.put(s, 0);
                    this.decodingLine(encoded);
                    this.println(line);
                }
            }
            line = fd.readLine();
        }

        fd.close();
        file.close();
    }

    /**
     * 用一明文匹配一密文
     *
     * @param encrypt
     * @param decrypted
     * @return 若匹配则返回映射好的密码表,否则返回null
     */
    public HashMap<Character, Character> decodingToken(char encrypt[],
            char decrypted[]) {
        HashMap<Character, Character> map = new HashMap<Character, Character>();
        for (int i = 0; i < encrypt.length; i++) {
            Character value = map.get(encrypt[i]);
            if (value != null && value != decrypted[i])
                return null;
            map.put(encrypt[i], decrypted[i]);
        }
        return map;
    }

    /**
     * 检查两个映射表的差异,前提是这两个映射表不冲突
     *
     * @param map
     * @param decriptedKey
     * @return
     */
    private HashMap<Character, Character> difference(
            HashMap<Character, Character> map,
            HashMap<Character, Character> decriptedKey) {
        HashMap<Character, Character> maped = new HashMap<Character, Character>();
        Set<Character> set = map.keySet();
        for (Character c : set) {
            Character value1 = map.get(c);
            if (!decriptedKey.containsKey(c))
                maped.put(c, value1);
        }
        return maped;
    }

    /**
     * 检查两个映射表是否冲突
     *
     * @param map
     * @param decriptedKey
     * @return
     */
    private boolean conflict(
            HashMap<Character, Character> map,
            HashMap<Character, Character> decriptedKey) {
        Set<Character> set = map.keySet();
        for (Character key1 : set) {
            Character value1 = map.get(key1);
            Set<Character> dec = decriptedKey.keySet();
            for (Character key2 : dec) {
                Character value2 = decriptedKey.get(key2);
                if ((!key1.equals(key2) && value1.equals(value2)) ||
                    (key1.equals(key2) && !value1.equals(value2))) {
                    return true;
                }
            }
        }
        return false;
    }

    private void increase(HashMap<Character, Character> map,
            HashMap<Character, Character> decriptedKey) {
        for (Character c : map.keySet()) {
            decriptedKey.put(c, map.get(c));
        }
    }

    private void decrease(HashMap<Character, Character> map,
            HashMap<Character, Character> decriptedKey) {
        for (Character c : map.keySet()) {
            decriptedKey.remove(c);
        }
    }

    /**
     * 解密单行
     * @param encoded
     */
    public void decodingLine(HashMap<String, Integer> encoded) {
        // 为每一行密文都重置秘密表
        decodingKey = new HashMap<Character, Character>();
        Set<String> set = encoded.keySet();
        int size= set.size();
        int pointer = 0;

        // 用于存放在set中每相邻的两个两个密文的解密密码表的delta,用于回溯时清除
        HashMap<?, ?> differences[] = new HashMap<?, ?>[size];

        while(pointer != size) {
            String encryptedItem = (String)set.toArray()[pointer];
            ArrayList<String> list = dict.get(encryptedItem.length());
            Integer index = encoded.get(encryptedItem);
            Integer iBak = index;

            // 已经处理过所有且已经回溯到了第一个链表的尾部了
            if (pointer == 0 && index == list.size()) {
                break;
            }

            // 遍历当前明文列表
            HashMap<Character, Character> map = null;
            while (index != list.size()) {
                map = decodingToken(encryptedItem.toCharArray(), list.get(index).toCharArray());
                if (map == null) {
                    index++;
                    continue;
                }
                else break;
            }

            // 无法匹配所有明文数组元素,意味着这个加密的单词无法解密
            if (index == list.size() && map == null) {
                if (iBak == 0) {
                    // 如果是当前列表里的明文都无法匹配密文,说明该密文无解
                    break;
                }

                // 否则的话回溯
                encoded.put(encryptedItem, 0);
                pointer--;

                // 删除之前的映射
                if (differences[pointer] != null) {
                    decrease((HashMap<Character, Character>)differences[pointer], decodingKey);
                    differences[pointer] = null;
                }
                continue;
            }

            // 判断解密的当前密码表和之前的密码表是否冲突
            boolean conf = conflict(map, decodingKey);
            if (conf == false) {
                // 更新当前匹配的明文索引
                encoded.put(encryptedItem, index + 1);

                // 记录密码表的delta
                HashMap<Character, Character> diff = difference(map, decodingKey);
                differences[pointer] = diff;
                if (diff != null) {
                    increase(diff, decodingKey);
                }
                pointer++;
                continue;
            }

            // 冲突处理,非回溯,继续查找列表的下一个元素
            encoded.put(encryptedItem, index + 1);
        }

        // failed to decrypt, set the encryptKey to null
        if (pointer != size) {
            decodingKey = null;
        }
    }

    public static void main(String[] args) throws Exception {
        Decoder decryp = new Decoder();
        decryp.decoding(args[0]);
    }
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值