Skip to content

举个例子……

  在往年的人工智能实验室招新考试中,有这样一道题目:

题目

要求:

将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度O(n),空间复杂度O(1)。

输入格式:

输入三行(多组实例测试),

第一行size(表示链表长度,0 < size <= 1000 );

第二行输入size个数,为每个节点对应值val(|val| <= 1000);

第三行为m,n(为反转区间的起止位置,0 < m <= n <= size)。

输出格式:

输出若干行,每行为每次区间反转后的结果。

  显然考官希望我们用 C 语言结构体指针或者 C++ 的 STL 标准库来解决问题。这道题 C 的标准答案如下:

c
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

 //节点 
typedef struct ListNode {
    int val;
    struct ListNode* next; 
}L;

//创建链表 
void CreateL(L** phead, int x) {
    L* newNode = (L*)malloc(sizeof(L));
    if (newNode == NULL) {
        perror("malloc fail!");
        return;
    }
    newNode => val = x;
    newNode => next = NULL;
    if (*phead == NULL) {
        *phead = newNode;
        return;
    }
    L* pcur = *phead;
    while (pcur => next) {
        pcur = pcur => next;
    }
    pcur => next = newNode;
}

//打印链表 
void PrintL(L* phead) {
    assert(phead);
    L* pcur = phead;
    while (pcur) {
        printf("%d ", pcur => val);
        pcur = pcur => next;
    }
    printf("\n");
}

//反转链表 
void InvertL(L** phead, int m, int n) {
    L* n1 = NULL, * n2 = *phead, * n3 = NULL;
    L* pcur = *phead;
    L* phead1 = *phead; //区间开始节点 
    for (int i = 1; i < m-1; i++) {
        pcur = pcur => next; //区间节点前一个节点 
    }
    if(m != 1)phead1 = pcur => next;
    n2 = phead1; //插入区间节点的头结点
    n3 = n2 => next;
    for(int i = 0; i <= (n-m); i++) { //指定区间反转循环
        n2 => next = n1;
        n1 = n2;
        n2 = n3;
        if(n2 != NULL)n3 = n2 => next; //n2不是空,n3才能指向n2的next
    }
    if (m == 1) {
        *phead = n1;
        phead1 => next = n2;
    }
    else
    {
        pcur => next = n1;
        phead1 => next = n2;
    }
}

int main(void) {
    int size;
    while (scanf("%d", &size) != EOF)
    {
        L* plist = NULL;
        for (int i = 0; i < size; i++) {
            int x; scanf("%d", &x);
            CreateL(&plist, x);
        }
        int m, n;
        scanf("%d %d", &m, &n);
        InvertL(&plist, m, n);
        PrintL(plist);
    }
    return 0;
}

  更加简洁的 C++ 标准答案是这样的[1]

cpp
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
#define endl '\n'

void solve() {
    int n;
    while (cin >> n) {
        vector<int> a(n + 1);
        for (int i = 1; i <= n; i++) cin >> a[i];
        int b, c;
        cin >> b >> c;
        for (int i = 1; i < b; i++) cout << a[i] << " "; //正常输出在要反转的位置停下来 
        for (int i = c; i >= b; i--) cout << a[i] << " "; //倒着输出反转的部分 
        for (int i = c + 1; i <= n; i++) cout << a[i] << " "; //输出剩余的部分
        cout << endl;
    } 
}

signed main() {
  ios::sync_with_stdio(false); //取消输入输出同步流,加快运行速度
  cin.tie(nullptr);
  solve();
  return 0;
}

  但是我提交的答案是这样的:

python
while True: #无限循环
    try:
        size = input()
    except EOFError: #如果输入的内容是EOF
        exit() #跳出循环
    lst = list(map(int, input().split())) 
    m, n = map(int, input().split()) 
    lst[m-1:n] = lst[m-1:n][::-1] #切片、反转列表
    print(' '.join(map(str, lst)))

  然后完美通过了这道题,用时仅为 C++ 选手的一半。

页面历史


  1. 这道题的 C++ 标准答案是一个 ACM 老登(此处指他染指计算机算法竞赛时间比较长)写的,他使用了取消输入输出流同步和 signed 类型的主函数写法,在非竞赛环境中用处不大。 ↩︎

Released under the CC BY-NC-SA 4.0 License

Copyright © 2024 DevBeginner-Doc