• 1025. 反转链表 (25)


    原题: https://www.patest.cn/contests/pat-b-practise/1025

    实现思路: 解决本题有2个关键点, 第1个是怎么把一堆打乱的链表节点, 按照头结点开始,
    排好序. 第2个是给我们按顺序的一组数字, 再给个K, 我们怎么对这组数进行正确翻转.
    也就是先解决:

    输入  
    00100 6 4
    00000 4 99999
    00100 1 12309
    68237 6 -1
    33218 3 00000
    99999 5 68237
    12309 2 33218  
    输出  
    00100 1 12309
    12309 2 33218
    33218 3 00000
    00000 4 99999
    99999 5 68237
    68237 6 -1
    

    然后解决:

    假设 k = 3
    输入: 1 2 3 4 5 6 7 8 9
    输出 3 2 1 6 5 4 8 9
    

    第1个关键点, 可以采用开一个10万空间的数组, 让address成为数组下标, 这样我们对数组按照
    头结点顺序排序时, 时间复杂只为n, 遍历一遍即可完成排序.
    第2个关键点, 比较容易, 在草稿纸上找找规律, 不难写出.

    注意本题最后一个测试的坑: 输入可能存在"报废节点", 所以录入数据时我们要检查next是否已经
    等于-1, 不能认为给n个数据, 链表中就一定有n个数据.

    版本1: 倒数第2个测试点运行超时, 无法AC

    #include <stdio.h>
    #include <stdlib.h>
    
    struct node {
        int address;
        int data;
        int next;
    };
    typedef struct node s_node;
    
    int find (s_node nd[], int n, int addr);
    void reverse (int source[], int dest[], int k, int n);
    
    int main () {
        int faddr;
        int n;
        int k;
        s_node *nd;
        s_node *temp;
        int addr;
        int i;
        int j;
        int x;
        int pos; // 根据地址找下标, 保存在此
        int *stnum; // 保存原来结构体的序号
        int *renum; // 保存反转后的序号
        int relen = 0; // 反转后的序号长度
    
        scanf("%d %d %d", &faddr, &n, &k);
        nd = (s_node*)malloc(sizeof(s_node) * (n + 1));
        temp = (s_node*)malloc(sizeof(s_node) * (n + 1));
        renum = (int*)malloc(sizeof(int) * (n + 1));
        stnum = (int*)malloc(sizeof(int) * (n + 1));
    
        for (i=1; i<=n; i++) {
            scanf("%d %d %d", &temp[i].address, &temp[i].data, &temp[i].next);
        }
        // 按照顺序, 进行排序赋值
        for (i=1; i<=n; i++) {
            pos = find(temp, n, faddr);
            nd[i] = temp[pos];
            faddr = temp[pos].next;
            if (faddr == -1) {
            // 排除程序中的废点
                n = i;
                break;
            }
        }
        free(temp);
        for (i=1; i<=n; i++) {
            stnum[i] = i;
        }
    
        // 反转序号
        reverse(stnum, renum, k, n);
        // 根据反转后的序号, 调整nd
        for (i=1; i<=n-1; i++) {
            j = renum[i];
            x = renum[i + 1];
            printf("%05d %d %05d
    ", nd[j].address, nd[j].data, nd[x].address);
        }
        // 最后一个数单独打印
        j = renum[n];
        printf("%05d %d %d
    ", nd[j].address, nd[j].data, -1);
    
        return 0;
    }
    
    // 返回地址是addr的节点下标
    int find (s_node nd[], int n, int addr) {
        int i;
        int pos = -1; // 等于-1说明没找到
        for (i=1; i<=n; i++) {
            if (nd[i].address == addr) {
                pos = i;
                break;
            }
        }
        return pos;
    }
    
    void reverse (int source[], int dest[], int k, int n) {
        int i; // i循环每次+k
        int j; // j用来表示有k层内循环
        int x; // 临时保存i的值
        int len = 0;
        for (i=k; i<=n; i+=k) {
            x = i;
            for (j=1; j<=k; j++) {
                len++;
                dest[len] = source[x];
                x--;
            }
        }
        // 最后不够的数, 加入末尾
        if (i != n) {
            for (j=i-(k-1); j<=n; j++) {
                len++;
                dest[len] = source[j];
            }
        }
    }
    

    版本2: 完整C语言实现 - 可以AC

    参考: http://www.xuebuyuan.com/2078825.html

    #include <stdio.h>
    #include <stdlib.h>
    
    struct node {
        int address;
        int data;
        int next;
    };
    typedef struct node s_node;
    
    void reverse (int source[], int dest[], int k, int n);
    
    int main () {
        int faddr;     // 首地址
        int n;         // 节点总数
        int k;         // 反转单位
        s_node *nd;    // 从头节点开始排好序, 存在这里
        s_node *temp;  // 从屏幕读入数据存入这里
        s_node tnode;  // 临时节点
        int *stnum;    // 保存原来结构体的序号
        int *renum;    // 保存反转后的序号
        int relen = 0; // 反转后的序号长度
        int i;
        int j;
        int x;
    
        scanf("%d %d %d", &faddr, &n, &k);
        nd = (s_node*)malloc(sizeof(s_node) * 100010);
        temp = (s_node*)malloc(sizeof(s_node) * 100010);
        renum = (int*)malloc(sizeof(int) * (n + 1));
        stnum = (int*)malloc(sizeof(int) * (n + 1));
    
        for (i=1; i<=n; i++) {
            scanf("%d %d %d", &tnode.address, &tnode.data, &tnode.next);
            temp[tnode.address] = tnode; // 这步非常关键, 开10万个空间, 用途就在这
        }
        // 从头地址开始, 按顺序赋值
        for (i=1; i<=n; i++) {
            nd[i] = temp[faddr];
            faddr = temp[faddr].next;
            if (faddr == -1) {
            // 排除报废节点
                n = i;
                break;
            }
        }
        free(temp); // 用不到了
        for (i=1; i<=n; i++) {
            stnum[i] = i;
        }
    
        // 反转序号
        reverse(stnum, renum, k, n);
        // 根据反转后的序号, 调整nd, 也就是调整打印顺序
        for (i=1; i<=n-1; i++) {
            j = renum[i];
            x = renum[i + 1];
            printf("%05d %d %05d
    ", nd[j].address, nd[j].data, nd[x].address);
        }
        // 最后一个数单独打印
        j = renum[n];
        printf("%05d %d %d
    ", nd[j].address, nd[j].data, -1);
    
        return 0;
    }
    
    void reverse (int source[], int dest[], int k, int n) {
        int i; // i循环每次+k
        int j; // j用来表示有k层内循环
        int x; // 临时保存i的值
        int len = 0;
        for (i=k; i<=n; i+=k) {
            x = i;
            for (j=1; j<=k; j++) {
                len++;
                dest[len] = source[x];
                x--;
            }
        }
        // 最后不够的数, 加入末尾
        if (i != n) {
            for (j=i-(k-1); j<=n; j++) {
                len++;
                dest[len] = source[j];
            }
        }
    }
    
    

    1025.jpg

  • 相关阅读:
    使用序列化实现对象的拷贝
    理解 Java 的三大特性之多态
    LeetCode OJ:Add and Search Word
    关于Qt的事件循环以及QEventLoop的简单使用
    LeetCode OJ:Generate Parentheses(括号生成)
    LeetCode OJ:Maximal Square(最大矩形)
    LeetCode OJ:Range Sum Query 2D
    LeetCode OJ:Power of Two(2的幂)
    LeetCode OJ:Longest Increasing Subsequence(最长递增序列)
    LeetCode OJ:Ugly Number II(丑数II)
  • 原文地址:https://www.cnblogs.com/asheng2016/p/7711439.html
Copyright © 2020-2023  润新知