[97. 邮件地址排序] 代码

Fifnmar edited 4 年,2 月前

讨论区放不下,有点长了。但我得吐糟一下,为什么 OJ 会直接吞了我辛苦写的东西 Orz


刚看这道题的时候,我好奇为什么是道 Hard 难度的题。现在看应该是因为数据量吧。

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
class Email {
    std::string user_name;
    std::string domain;

  public:
    Email(std::string const &raw_address) {
        auto at_pos = raw_address.find('@');
        assert(at_pos != std::string::npos);
        user_name = raw_address.substr(0, at_pos);
        domain = raw_address.substr(at_pos + 1);
    }

    bool operator<(Email const &rhs) const {
        if (domain == rhs.domain) {
            return user_name > rhs.user_name;
        } else {
            return domain < rhs.domain;
        }
    }

    std::ostream &output_full_address(std::ostream &out) const {
        return out << user_name << '@' << domain;
    }
};

int main() {
    using namespace std;
    uint32_t n; cin >> n;
    vector<Email> emails;
    for (uint32_t i = 0; i < n; ++i) {
        string temp; cin >> temp;
        emails.push_back({temp});
    }
    sort(emails.begin(), emails.end());
    for (auto const &i : emails) {
        i.output_full_address(cout) << '\n';
    }
}

有同学想看 C 语言的写法,我用同样的思想重写了一下。

#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// I extract a struct of Dynamic string out here,
// making it a separate struct. Actually we can
// make an integrated struct `Email` and handle
// all the work inside, which will reduce the
// code length for this of our need.
// ********************************************* //

// Handle to a dynamic string;
typedef struct {
    char *raw_str;
    size_t size; // Always less than _reserve.
    size_t _reserve;
} Dynstr;

// DOES NOT guarantee against EOF.
// Reads one more space and then discard it.
Dynstr read_dynstr(FILE *read_source) {
    Dynstr ret;
    ret.size = 0;
    ret.raw_str = (char *)malloc(sizeof(char) * 16);
    ret._reserve = 16;
    int ch;
    while (isspace(ch = getc(read_source))) {
        assert(ch != EOF);
    }
    do {
        ret.raw_str[ret.size++] = ch;
        if (ret.size == ret._reserve) {
            char *temp = (char *)malloc(sizeof(char) * (ret._reserve <<= 1));
            memcpy(temp, ret.raw_str, ret.size);
            free(ret.raw_str);
            ret.raw_str = temp;
        }
        ch = getc(read_source);
    } while (!isspace(ch));
    ret.raw_str[ret.size] = '\0';
    return ret;
}

typedef struct {
    // I choose to use (ptr, size) instead of (begin, end),
    // in respect of C conventions.
    Dynstr const *_raw_address_view;
    char *user_name_bg;
    char *domain_bg;
    size_t user_name_size;
    size_t domain_size;
} hdlEmail; // handle to Email.

hdlEmail get_email_handle(Dynstr const *full_address) {
    hdlEmail ret;
    char *iter = full_address->raw_str;
    for (; *iter != '@'; ++iter) {
        assert((size_t)(iter - full_address->raw_str) < full_address->size);
    }
    ret._raw_address_view = full_address;
    ret.user_name_bg = full_address->raw_str;
    ret.user_name_size = iter - ret.user_name_bg;
    ret.domain_bg = iter + 1;
    ret.domain_size = full_address->size - ret.user_name_size - 1;
    return ret;
}

// Unsafe: Breaks the `const` and temporarily changes the key strings.
int hdlEmail_cmp(void const *_lhs, void const *_rhs) {
    *(((hdlEmail *)_lhs)->domain_bg - 1) = '\0';
    int a = strcmp(((hdlEmail *)_lhs)->domain_bg, ((hdlEmail *)_rhs)->domain_bg);
    if (a == 0)
        a = strcmp(((hdlEmail *)_rhs)->user_name_bg, ((hdlEmail *)_lhs)->user_name_bg);
    *(((hdlEmail *)_lhs)->domain_bg - 1) = '@';
    return a;
}

int main() {
    uint32_t n; scanf("%u", &n);
    Dynstr *strarr = (Dynstr *)malloc(sizeof(Dynstr) * n);
    hdlEmail *hdlarr = (hdlEmail *)malloc(sizeof(hdlEmail) * n);
    for (uint32_t i = 0; i < n; ++i) {
        strarr[i] = read_dynstr(stdin);
        hdlarr[i] = get_email_handle(strarr + i);
    }
    qsort(hdlarr, n, sizeof(hdlEmail), hdlEmail_cmp);
    for (uint32_t i = 0; i < n; ++i) {
        printf("%s\n", hdlarr[i]._raw_address_view->raw_str);
    }
    free(strarr);
}

可以看出要手动撸一些东西。实际上如果不是在做题的话还是可以找到很多基础库,用起来应该也能行,没必要自己写。

效率上,我的 C 代码跟 C++ 代码不相上下,可能是因为思路基本是相同的叭。

// 这道题又是劝同学们放弃 C 语言的一个铁证(滑稽),珍爱生命,远离 C 语言。

Comments