• 分享一道手搓链表玩矩阵的算法题


    !!!用java开发思维写算法,不喜勿喷,本人没有强化过自己的算法水平,属于算法菜鸟一只。

    先来看看题目:(我做的时候看见全英的我也有点上头,不过还好不是英盲哈哈哈哈哈)

    Background

    A text string can be encoded into a digits string with a Square like below:

    12345
    1ABCDE
    2FGHI/JK
    3LMNOP
    4QRSTU
    5VWXYZ

    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.

    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.

    12345
    1RI/JPLE
    2ABCDF
    3GHKMN
    4OQSTU
    5VWXYZ

    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

    1. NO WAR, NO PAIN
    2. 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在同一个结点里,我给结点设置两种有参构造,左右我嫌太麻烦就直接不用它们了)

    1. /**
    2. * 定义每个节点的结构
    3. */
    4. class Node {
    5. int left;
    6. int right;
    7. char value;
    8. char value1;
    9. public Node( char value) {
    10. this.value = value;
    11. }
    12. public Node(char value, char value1) {
    13. this.value = value;
    14. this.value1 = value1;
    15. }
    16. }

    然后我们由于需要基于List去做,但是List提供的方法和我们需要的还是有差别的,我来封装一个新的NodeList去解决这个问题,应对我们自己的场景需要:

    NodeList.java

    1. /**
    2. * 封装节点到简单的链表中
    3. */
    4. class NodeList {
    5. public static List nodeList = new LinkedList<>();
    6. /**
    7. * 在尾部插入元素
    8. *
    9. * @param node 节点
    10. * @return 是否成功
    11. */
    12. public static Boolean insertNode(Node node) {
    13. return nodeList.add(node);
    14. }
    15. /**
    16. * 在指定索引处插入节点
    17. *
    18. * @param node 新节点
    19. * @param index 索引
    20. */
    21. public static void insertNodeByIndex(Node node, int index) {
    22. try {
    23. nodeList.add(index, node);
    24. }catch (Exception e){
    25. e.printStackTrace();
    26. }
    27. }
    28. /**
    29. * 删除值为某个字符的节点
    30. *
    31. * @param value 指定值
    32. * @return 是否成功
    33. */
    34. public static Boolean deleteNode(char value) {
    35. /*如果节点的值一样就会直接删除*/
    36. return nodeList.removeIf(n -> (n.value == value || n.value1 == value));
    37. }
    38. /**
    39. * 判断我们的链表中是否存在某一值为value的节点
    40. *
    41. * @param value 指定值
    42. * @return 是否存在
    43. */
    44. public static Boolean containsValue(char value) {
    45. boolean sign = false;
    46. for (Node node : nodeList) {
    47. if (node.value == value || node.value1 == value) {
    48. sign = true;
    49. break;
    50. }
    51. }
    52. return sign;
    53. }
    54. /**
    55. * 根据输入的英文文本删除链表中它所含有的字符的节点
    56. *
    57. * @param charSqueue 英文文本的字符序列
    58. * @return 是否删除成功
    59. */
    60. public static Boolean clearNode(String charSqueue) {
    61. boolean sign = true;
    62. for (char i : charSqueue.toCharArray()) {
    63. if (containsValue(i))
    64. sign = sign && deleteNode(i);
    65. }
    66. return sign;
    67. }
    68. /**
    69. * 将输入的英文文本按顺序插到链表左侧按照原文本的序列
    70. * @param charSqueue 英文文本的字符序列
    71. */
    72. public static void insertNodeByEnglishString(String charSqueue){
    73. int index = 0;
    74. for (char i : charSqueue.toCharArray()){
    75. if (!containsValue(i)){
    76. Node node = new Node(i);
    77. insertNodeByIndex(node, index);
    78. index++;
    79. }
    80. }
    81. }
    82. /**
    83. * 根据转换过来的索引获取某个字母或者特殊字符
    84. *
    85. * @param index 转换的索引
    86. * @return 大写字母或者是特殊字符
    87. */
    88. public static char getNodeValueByIndex(int index) {
    89. if (index == -1)
    90. return ' ';
    91. if (index == -2)
    92. return '/';
    93. if (index == -3)
    94. return ',';
    95. if (index == -4)
    96. return '.';
    97. if (nodeList.get(index - 1).value1 == 'J')
    98. return 'J';
    99. return nodeList.get(index - 1).value;
    100. }
    101. }

    最后我们还需要在具体的实现类里写一些简单的工具方法,实现代码的复用,减少重复代码:

    Quiz.java

    1. /**
    2. * 利用链表实现,自定义节点对象,暂无优化,存在I/J的冲突
    3. */
    4. public class Quiz {
    5. /**
    6. * 获取初始化链表
    7. *
    8. * @return 初始化正常排序的链表
    9. */
    10. public static List getInitNodeList() {
    11. for (int i = 65; i <= 90; i++) {
    12. Node node;
    13. if (i == 73) {
    14. node = new Node( (char) i, (char) ++i);
    15. } else {
    16. node = new Node((char) i);
    17. }
    18. try {
    19. Boolean insertNode = NodeList.insertNode(node);
    20. } catch (Exception e) {
    21. e.printStackTrace();
    22. }
    23. }
    24. return NodeList.nodeList;
    25. }
    26. /**
    27. * 转换矩阵坐标为链表索引
    28. *
    29. * @param X 行数 从1开始到5结束
    30. * @param Y 列数 从1开始到5结束
    31. * @return 链表中的索引与特殊含义数字
    32. */
    33. public static int getIndexByXY(int X, int Y) {
    34. /*规定只能在五乘五的矩阵中由坐标翻译成链表中的索引*/
    35. if (X > 5 || Y > 5)
    36. return 0;
    37. if (X == 0 && Y == 0)
    38. return -1;
    39. if (X == 1 && Y == 0)
    40. return -2;
    41. if (X == 0 && Y == 1)
    42. return -3;
    43. if (X == 0 && Y == 2)
    44. return -4;
    45. return (X - 1) * 5 + Y;
    46. }
    47. /**
    48. * 将输入的字符串数字队列转换成数字队列放在链表里
    49. *
    50. * @param numericSqueue 字符串数字队列
    51. * @return 整型的数字链表
    52. */
    53. public static List getBeforeHandleString(String numericSqueue) {
    54. char[] charArray = numericSqueue.toCharArray();
    55. List newCharArray = new ArrayList<>();
    56. for (char i : charArray) {
    57. newCharArray.add(((int) i) - 48);
    58. }
    59. return newCharArray;
    60. }
    61. /**
    62. * 判断输入的是英文文本还是数字序列并获取输入信息
    63. *
    64. * @return 输入的字串
    65. */
    66. public static String getUserInPutString() {
    67. System.out.println("输入你想输入的字串!");
    68. Scanner scanner = new Scanner(System.in);
    69. return scanner.nextLine();
    70. }
    71. /**
    72. * 处理输入的是数字序列信息的情况
    73. */
    74. public static void transferNumericSqueue(String cherSqueue) {
    75. List beforeHandleString = getBeforeHandleString(cherSqueue);
    76. int X = 0;
    77. int Y = 1;
    78. while (Y <= beforeHandleString.size()) {
    79. int index = getIndexByXY(beforeHandleString.get(X), beforeHandleString.get(Y));
    80. char nodeChar = NodeList.getNodeValueByIndex(index);
    81. if (nodeChar == '/') {
    82. System.out.println();
    83. } else
    84. System.out.print(nodeChar);
    85. X = X + 2;
    86. Y = Y + 2;
    87. }
    88. }
    89. /**
    90. * 根据英文文本序列更改链表 先删在插
    91. * @param charSqueue 英文文本的字符序列
    92. */
    93. public static void updateInitNodeList(String charSqueue){
    94. NodeList.nodeList = getInitNodeList();
    95. for(Node node : NodeList.nodeList)
    96. System.out.print(node.value);
    97. System.out.println();
    98. Boolean clearNode = NodeList.clearNode(charSqueue);
    99. NodeList.insertNodeByEnglishString(charSqueue);
    100. for(Node node : NodeList.nodeList)
    101. System.out.print(node.value);
    102. }
    103. public static void main(String[] args) {
    104. String inPutString = getUserInPutString();
    105. System.out.println();
    106. if ((int)inPutString.charAt(0) >= 65 && (int)inPutString.charAt(0) <90 ){
    107. updateInitNodeList(inPutString);
    108. System.out.println("你的矩阵重排成功!再次输入你想要解码的数字序列,注意需要是偶数个!");
    109. String towInPutString = getUserInPutString();
    110. transferNumericSqueue(towInPutString);
    111. }else {
    112. getInitNodeList();
    113. transferNumericSqueue(inPutString);
    114. }
    115. }
    116. }

    算法的最终答案?来看看测试结果:

     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

     所以这个算法题的大哥还是很幽默的,做完了!258行代码,不建议专业的算法大佬们学习,这么长的代码也就玩玩而已啦。

  • 相关阅读:
    small synopsis - MYSQL for beginners
    Unity ECS最新DOTS环境搭建教程
    HyperLynx(二十八)板层噪声分析和SI/PI联合仿真实例
    vue3+TS前端JS实现 搜索关键词变红
    Jenkins pipeline中的全局变量
    Go语言类库-reflect(反射)
    SpringBoot--中间件技术-3:整合mongodb,整合ElasticSearch,附案例含代码(简单易懂)
    【算法挨揍日记】day14——724. 寻找数组的中心下标、238. 除自身以外数组的乘积
    NIO Channel(通道)类
    Java-GUI编程之菜单组件
  • 原文地址:https://blog.csdn.net/m0_59588838/article/details/126233798