后端工程师-头条笔试

这是一个包含两个技术问题的博客。第一个问题是关于如何映射字符到数字,以使由字符串组成的整数之和最大化,每个字符串不能有前导零。第二个问题涉及构建面积大于0的简单多边形,需要根据一系列插入和删除木棒的操作判断是否能形成这样的多边形。题目还提供了输入输出描述和条件约束。
摘要由CSDN通过智能技术生成

2017

1、有 n 个字符串,每个字符串都是由 A-J 的大写字符构成。现在你将每个字符映射为一个 0-9 的数字,不同字符映射为不同的数字。这样每个字符串就可以看做一个整数,唯一的要求是这些整数必须是正整数且它们的字符串不能有前导零。现在问你怎样映射字符才能使得这些字符串表示的整数之和最大?

就是利用权重来计算
输入例子:
ABC
BCA
设 table = A B C D E F G H I J
个位权值 为 1
十位权值 为 10
百位权值 为 100
依次类推, 没有出现的字母权值为 0

则 A 的权重为 100 + 1  = 101
B 的权重为    10 + 100 = 110
C 的权重为    1 + 10   = 11
D - J 的权重为   0
即 依照 table 的字母排列顺序,权重表为
weight = 101  110 11 0 0 0 0 0 0 

进而得到
映射值表
ret    = 8    9   7 0 0 0 0 0 0 
将 (权重表 x 映射表),然后再累加起来就是题目要的答案
则这些数的和为 (101 * 8) + (110 * 9) + (11 * 7) + 0 + ... + 0 = 1875 
具体细节 和 实现代码如下
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <math.h>
#include <assert.h>
#include <cstring>
using namespace std;
 
typedef unsigned long long ULL; // 最大要计算 12 位的正整数,所以还是用一个大点的类型吧
 
// 依据权重表 weight, 得到映射表 ret (即: 排位)
// 比如:
//
// | table |  A     |    B     | C  | D      | E     | F    | G | H   | I   | J    |
// |-------|--------|----------|----|--------|-------|------|---|-----|-----|------|
// | weight|10000001| 1010001  | 20 | 100000 | 10000 | 1000 | 1 | 100 | 110 | 1000 |
// |-------|--------|----------|----|--------|-------|------|---|-----|-----|------|
// | ret   |  9     |   8      |  1 |    7   |   6   |   5  | 0 |  2  |  3  |   4  |
//
void map_weight(ULL* weight, int* ret, const int n = 10) {
    //
    // 排位算法:
    // 初值都为 9 
    // C(10, 2) : 从10个数中挑选两个数。
    // 比较这两个数:谁小谁减一,相等的话随便挑选一个减一
    //
    assert(n == 10);
    for (int i = 0; i < n; ++i) {
        ret[i] = 9;
    }
 
    for (int i = 0; i < n; ++i) {
        if (weight[i] == 0) {
            ret[i] = 0;
            continue;
        }
        for (int j = i + 1; j < n; ++j) {
            if (weight[j] == 0) {
                ret[j] = 0;
                continue;
            }
            if (weight[i] < weight[j]) {
                ret[i]--;
            }
            else {
                ret[j]--;
            }
            // 因为映射不能重复,
            // 所以当 weight[i] == weight[j] 权重相等时,
            // 随意挑选一个减一即可。
            // 例如: 'A' 和 'B' 权重值相等,但不能都映射为 9
            // 此时,随意挑选一个使其映射值 减一 即可 9, 8
        }
    }
}
 
// 判断给定的字符 c 是否在 input 中有作为首字符出现
bool is_header(const char c, const vector<string>& input) {
    const size_t len = input.size();
    for (size_t i = 0; i < len; ++i) {
        if (c == input[i][0])
            return true;
    }
    return false;
}
 
// 依据给定的值,在映射表 ret 中查找对应的下标 (可进一步优化)
int get_pos(const int value, const int* ret, const int n = 10) {
    for (int i = 0; i < n; ++i) {
        if (value == ret[i])
            return i;
    }
    return -1;
}
 
// 因为不能有 0 开头的数字,所以要修正一下映射表 ret
void fixed_ret(int *ret, char *table, const vector<string>& input,
        const int n = 10) {
    int pos_0 = get_pos(0, ret);
    assert(pos_0 >= 0);
 
    if (! is_header(table[pos_0], input)) return;
    // 当前序列需调整
 
    // 依次查找 最小非开头的映射值 i
    int opt_pos = -1;
    for (int i = 1; i < n; ++i) {
        int pos = get_pos(i, ret);
        assert(pos >= 0);
        if (! is_header(table
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值