• 【Zhejiang University PATest】02-1. Reversing Linked List


    Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.

    Input Specification:

    Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (<= 105) which is the total number of nodes, and a positive K (<=N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.

    Then N lines follow, each describes a node in the format:

    Address Data Next

    where Address is the position of the node, Data is an integer, and Next is the position of the next node.

    Output Specification:

    For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.

    Sample Input:
    00100 6 4
    00000 4 99999
    00100 1 12309
    68237 6 -1
    33218 3 00000
    99999 5 68237
    12309 2 33218
    
    Sample Output:
    00000 4 33218
    33218 3 12309
    12309 2 00100
    00100 1 99999
    99999 5 68237
    68237 6 -1
    

    【solution】
    初看题意,很简明易懂。(不要被表象迷惑了。。
    链表嘛,还手动给出了节点地址,于是开始写。
    等我经历了一番折腾之后,我觉得这道题堪称打表神题,因为它实在是把这个点用表象隐藏得很好。想明白了之后实现就并不难了。

    说下我的“心路历程”:
    很快发现这题的关键在于“段与段”之间的“地址”连接处要处理好。
    一开始,特意用结构体来构造出节点,三个成员,data, addr(自己的地址),next(下一个节点地址),其中地址用字符串来存储,然后创造一个元素是结构体的数组(得强调一下物理地址是相邻的一块内存)。
    很自然的,我开始用输入数据构造一个串。怎么构造呢?地址都是字符串,又很自然的,随手开始暴力查找下一个节点,显然是个O(n^2)的。然后想,我擦,不会过不了吧。有优化吗?一时并没有想到(与字符串存地址的先入思维有关)。
    然后想,唉这才第二周第一道题,测试数据应该不会很坑吧。(事实上我已经掉坑里了 T_T)

    然后写完一测试,一个点超时,一个点竟然还WA了!超时还可以理解,竟然还有WA!
    然后首先开始解决WA的问题(因为超时可能也是程序对某些测例出错引起的)。再看代码,边界情况应该都没有问题啊。
    在讨论区受陈越姥姥提醒,输入数据中的节点竟然有可能不在有效的需要输出的链上!也就是最后输出的链长可能没有 n !因为输入里面有无效节点!T_T
    姥姥(出题人)真是心思缜密啊![苦笑]

    然后WA解决了,可是还是有超时。
    看来问题是出在 O(n^2) 的构造链上。
    再看代码,觉得可能是地址复制来复制去的字符串操作影响了效率,这才终于开始思考把地址用整型来存储。
    马上把地址改成了整型,还是超时。
    问姥姥,姥姥说是有点小技巧,复杂度是 O(n) 的。
    竟然是 O(n) 的!!我才开始认真思考起优化来。
    是不是要排序啊?给地址排个序然后二分查找?即便如此也是 O(nlogn) 啊。而且第二周诶,还没讲诶,不会这么复杂吧。[再次苦笑]
    开始还一直桎梏于地址为字符串的思路里,甚至想到了 哈希表、优先级队列、完全二叉堆 等等数据结构。可是这才第二周啊![大声苦笑加自嘲]
    大概是习惯了打表对于大多数题肯定不会是标准解法(其原因在于题目数据范围一般较大),慢慢的忘了“初心”了。[骗分导论加苦笑!]
    这道题真的隐藏得很好,姥姥真是有心了。

    思维经历一番千回百转的浪潮,终于想到了将地址作为数组的数值下标,而数组值是数据内容以及下一个节点地址这种被我称作“打表”的办法。
    不禁一阵唏嘘啊 T_T

    有几点要说:
    1、不要小看任何一道题;
    2、这道题真正巧妙的揭示了列表和向量的区别与本质,看似题目是列表,实际做起来却是向量(利用向量键值对O(1)的查找,也就是所谓的打表。。);
    3、代码中,输出前导0的格式控制:%05d。向右对齐,最少占5位,不足用0填补。要注意最后一个 -1 需要特殊判断(否则输出 -0001 )。

    AC代码如下,可能空间上还可以优化,由于我为了尽可能少改动原始版的代码就不做大幅改动了:
     1 #include <stdio.h> 
     2 #include <malloc.h>
     3 
     4 #define AddrMAX 1000004
     5 
     6 typedef struct AnsNode
     7 {
     8     int addr, data;
     9 }anode, *panode;
    10 
    11 int main(void)
    12 {
    13     int n, k, i, j, block, rest, top = 0;
    14     int start, temp;
    15     
    16     scanf("%d %d %d", &start, &n, &k);
    17     
    18     int* data = (int *)malloc(sizeof(int)*(AddrMAX));
    19     int* next = (int *)malloc(sizeof(int)*(AddrMAX));
    20     
    21     panode ans = (panode)malloc(sizeof(anode)*(n+1));
    22     
    23     for (i = 0; i < n; i++)
    24     {
    25         scanf("%d", &temp);
    26         scanf("%d %d", &data[temp], &next[temp]);
    27     }
    28     
    29     // 按地址将链构造好放入ans中 
    30     while (start != -1)
    31     {
    32         ans[top].data = data[start];
    33         ans[top].addr = start;
    34         start = next[start];
    35         top++;
    36     }
    37     n = top;
    38     
    39     // 每 K 段输出一次,并且处理最后一次不足k个的情况,关键点在于“段与段”之间“地址 ”的拼接 
    40     block = n / k; rest = n % k;
    41     for (j = 0; j < block; j++)
    42     {
    43         for (i = (j + 1)*k - 1; i > j*k; i--)
    44         {
    45             printf("%05d %d %05d
    ", ans[i].addr, ans[i].data, ans[i-1].addr);
    46         }
    47         printf("%05d %d ", ans[i].addr, ans[i].data);
    48         if (rest == 0)
    49         {
    50             if (j == block - 1) printf("-1");
    51             else printf("%05d", ans[(j+2)*k-1].addr);
    52         } else
    53         {
    54             if (j == block - 1) printf("%05d", ans[(j+1)*k].addr);
    55             else printf("%05d", ans[(j+2)*k-1].addr);
    56         }
    57         printf("
    ");
    58     }
    59     if (rest != 0)
    60     {
    61         for (i = block*k; i < n - 1; i++) printf("%05d %d %05d
    ", ans[i].addr, ans[i].data, ans[i+1].addr);
    62         printf("%05d %d -1
    ", ans[i].addr, ans[i].data);
    63     }
    64     
    65     return 0;
    66 }
  • 相关阅读:
    Win10安装组策略功能
    IIS 站点批量迁移
    MongoDB 异常记录
    微信Web开发者工具
    NHibernate 异常
    Git 常用命令
    IIS 反向代理
    CSS应用
    Oracle
    Android之ActionBar学习
  • 原文地址:https://www.cnblogs.com/maples7/p/4153984.html
Copyright © 2020-2023  润新知