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