!!!用java开发思维写算法,不喜勿喷,本人没有强化过自己的算法水平,属于算法菜鸟一只。
先来看看题目:(我做的时候看见全英的我也有点上头,不过还好不是英盲哈哈哈哈哈)
Background
A text string can be encoded into a digits string with a Square like below:
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | A | B | C | D | E |
2 | F | G | H | I/J | K |
3 | L | M | N | O | P |
4 | Q | R | S | T | U |
5 | V | W | X | Y | Z |
The 26 letters of the English alphabet do not fit in a 5 × 5 square, I and J are combined.
For example, "BAT" becomes "121144" because B -> 12, A -> 11, T -> 44.
"JEDI" becomes "24151424" because J -> 24, E -> 15, D -> 14, I -> 24.
A key could be used to reorder the alphabet in the square, with the letters (without duplicates) of the key being placed at the beginning and the remaining letters following it in alphabetical order. For example, the key phrase "RIPPLE" would lead to the reordered square below.
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | R | I/J | P | L | E |
2 | A | B | C | D | F |
3 | G | H | K | M | N |
4 | O | Q | S | T | U |
5 | V | W | X | Y | Z |
With this Square, "MAP" becomes "342113" because M -> 34, A -> 21, P -> 13.
By adding fixed mappings below, we can encode some real text.
Space -> 00
New Line -> 10
, -> 01 //Comma
. -> 02 //Period
With key phrase "RIPPLE" and text below
NO WAR, NO PAIN
LOVE AND PEACE
The encoded digits will be
354100522111010035410013211235101441511500213524001315212315
Question
With key phrase "FINAL FANTASY" and digits string
533432133252324500221413330041230022421333221042130021343200222114333201004213004123004253131053343213325232450022141231004123005342453
来分析分析:
需要注意实现的点:
1、我们需要实现一个链表让它能够通过两个数字去定位到链表中的某一元素(链表插入快,删除也快,我们最下面的要求就是实现重排矩阵,至于搜索速度慢我们暂且不论,纯java手搓,有优化的兄弟可以来分享一下你的想法)
2、需要实现初始矩阵的List实现,每一个字母存在一个结点对象里,需要实现坐标与索引的换算,需要实现一整串数字串的每两个数字的成组运算。
3、在输入英文文本重排矩阵的时候,需要判断有没有已经操作过的字符或者待插入的字符是否不存在了?如果输入FASTA那么A重复了就不能二次插入直接忽略。
重要的点就这几个啦,因为5X5的矩阵最多放25个元素,这里的I和J他给到一个位置里了,至于你判断输出I还是J?得靠自己的英语水平,程序毕竟不会有感情的根据英文输出的意思给你替换I与J。
手写java代码干它!
首先我做一个基本结点的类:
Node.java(考虑到I与J在同一个结点里,我给结点设置两种有参构造,左右我嫌太麻烦就直接不用它们了)
/**
* 定义每个节点的结构
*/
class Node {
int left;
int right;
char value;
char value1;
public Node( char value) {
this.value = value;
}
public Node(char value, char value1) {
this.value = value;
this.value1 = value1;
}
}
然后我们由于需要基于List去做,但是List提供的方法和我们需要的还是有差别的,我来封装一个新的NodeList去解决这个问题,应对我们自己的场景需要:
NodeList.java
/**
* 封装节点到简单的链表中
*/
class NodeList {
public static List<Node> nodeList = new LinkedList<>();
/**
* 在尾部插入元素
*
* @param node 节点
* @return 是否成功
*/
public static Boolean insertNode(Node node) {
return nodeList.add(node);
}
/**
* 在指定索引处插入节点
*
* @param node 新节点
* @param index 索引
*/
public static void insertNodeByIndex(Node node, int index) {
try {
nodeList.add(index, node);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 删除值为某个字符的节点
*
* @param value 指定值
* @return 是否成功
*/
public static Boolean deleteNode(char value) {
/*如果节点的值一样就会直接删除*/
return nodeList.removeIf(n -> (n.value == value || n.value1 == value));
}
/**
* 判断我们的链表中是否存在某一值为value的节点
*
* @param value 指定值
* @return 是否存在
*/
public static Boolean containsValue(char value) {
boolean sign = false;
for (Node node : nodeList) {
if (node.value == value || node.value1 == value) {
sign = true;
break;
}
}
return sign;
}
/**
* 根据输入的英文文本删除链表中它所含有的字符的节点
*
* @param charSqueue 英文文本的字符序列
* @return 是否删除成功
*/
public static Boolean clearNode(String charSqueue) {
boolean sign = true;
for (char i : charSqueue.toCharArray()) {
if (containsValue(i))
sign = sign && deleteNode(i);
}
return sign;
}
/**
* 将输入的英文文本按顺序插到链表左侧按照原文本的序列
* @param charSqueue 英文文本的字符序列
*/
public static void insertNodeByEnglishString(String charSqueue){
int index = 0;
for (char i : charSqueue.toCharArray()){
if (!containsValue(i)){
Node node = new Node(i);
insertNodeByIndex(node, index);
index++;
}
}
}
/**
* 根据转换过来的索引获取某个字母或者特殊字符
*
* @param index 转换的索引
* @return 大写字母或者是特殊字符
*/
public static char getNodeValueByIndex(int index) {
if (index == -1)
return ' ';
if (index == -2)
return '/';
if (index == -3)
return ',';
if (index == -4)
return '.';
if (nodeList.get(index - 1).value1 == 'J')
return 'J';
return nodeList.get(index - 1).value;
}
}
最后我们还需要在具体的实现类里写一些简单的工具方法,实现代码的复用,减少重复代码:
Quiz.java
/**
* 利用链表实现,自定义节点对象,暂无优化,存在I/J的冲突
*/
public class Quiz {
/**
* 获取初始化链表
*
* @return 初始化正常排序的链表
*/
public static List<Node> getInitNodeList() {
for (int i = 65; i <= 90; i++) {
Node node;
if (i == 73) {
node = new Node( (char) i, (char) ++i);
} else {
node = new Node((char) i);
}
try {
Boolean insertNode = NodeList.insertNode(node);
} catch (Exception e) {
e.printStackTrace();
}
}
return NodeList.nodeList;
}
/**
* 转换矩阵坐标为链表索引
*
* @param X 行数 从1开始到5结束
* @param Y 列数 从1开始到5结束
* @return 链表中的索引与特殊含义数字
*/
public static int getIndexByXY(int X, int Y) {
/*规定只能在五乘五的矩阵中由坐标翻译成链表中的索引*/
if (X > 5 || Y > 5)
return 0;
if (X == 0 && Y == 0)
return -1;
if (X == 1 && Y == 0)
return -2;
if (X == 0 && Y == 1)
return -3;
if (X == 0 && Y == 2)
return -4;
return (X - 1) * 5 + Y;
}
/**
* 将输入的字符串数字队列转换成数字队列放在链表里
*
* @param numericSqueue 字符串数字队列
* @return 整型的数字链表
*/
public static List<Integer> getBeforeHandleString(String numericSqueue) {
char[] charArray = numericSqueue.toCharArray();
List<Integer> newCharArray = new ArrayList<>();
for (char i : charArray) {
newCharArray.add(((int) i) - 48);
}
return newCharArray;
}
/**
* 判断输入的是英文文本还是数字序列并获取输入信息
*
* @return 输入的字串
*/
public static String getUserInPutString() {
System.out.println("输入你想输入的字串!");
Scanner scanner = new Scanner(System.in);
return scanner.nextLine();
}
/**
* 处理输入的是数字序列信息的情况
*/
public static void transferNumericSqueue(String cherSqueue) {
List<Integer> beforeHandleString = getBeforeHandleString(cherSqueue);
int X = 0;
int Y = 1;
while (Y <= beforeHandleString.size()) {
int index = getIndexByXY(beforeHandleString.get(X), beforeHandleString.get(Y));
char nodeChar = NodeList.getNodeValueByIndex(index);
if (nodeChar == '/') {
System.out.println();
} else
System.out.print(nodeChar);
X = X + 2;
Y = Y + 2;
}
}
/**
* 根据英文文本序列更改链表 先删在插
* @param charSqueue 英文文本的字符序列
*/
public static void updateInitNodeList(String charSqueue){
NodeList.nodeList = getInitNodeList();
for(Node node : NodeList.nodeList)
System.out.print(node.value);
System.out.println();
Boolean clearNode = NodeList.clearNode(charSqueue);
NodeList.insertNodeByEnglishString(charSqueue);
for(Node node : NodeList.nodeList)
System.out.print(node.value);
}
public static void main(String[] args) {
String inPutString = getUserInPutString();
System.out.println();
if ((int)inPutString.charAt(0) >= 65 && (int)inPutString.charAt(0) <90 ){
updateInitNodeList(inPutString);
System.out.println("你的矩阵重排成功!再次输入你想要解码的数字序列,注意需要是偶数个!");
String towInPutString = getUserInPutString();
transferNumericSqueue(towInPutString);
}else {
getInitNodeList();
transferNumericSqueue(inPutString);
}
}
}
算法的最终答案?来看看测试结果:
WHENEVER SANG MY SONGS
ON THE STAGE, ON MY OWN
WHENEVER SAID MY WORDS
WISHING THEY WOULD BE HEARD
I SAW YOU SMILING AT ME
WAS IT REAL OR JUST MY FANTASY