我将 ASCII 单词转换为数字,但在尝试解码它们时遇到了困难。如何转换 1=a、2=b、28=ab 等? (伪代码好吧)

问题描述 投票:0回答:5

所以我想自学 C++,但我似乎对这门语言没有任何问题,但坦率地说我很愚蠢。

所以我的想法是这样的。如果我说 a=1、b=2、z=26、aa=27 等,我可以将单词映射到数字,在哈希表中使用布尔值(当然是位掩码),并有一个 O(1) 拼写检查器。所以这样写完全没有问题。我的算法是这样的:

int pos;
word_key_t char_key;
word_key_t key = 0;
const char *raw = word.c_str();

cout << "Entering getKey loop with " << raw << endl;
for (pos = 0; raw[pos] != '\0'; pos++) {
    if (raw[pos] >= 'A' && raw[pos] <= 'Z') {
        char_key = raw[pos] - 'A';
    } else if (raw[pos] >= 'a' && raw[pos] <= 'z') {
        char_key = raw[pos] - 'a';
    } else {
        throw new runtime_error("Unrecognised Character");
    }

    key += (char_key + 1) * (pow(CHARS_IN_ALPHABET, pos));
}

cout << "word: " << raw << " ,score: " << key << endl;
return key;

看起来有效,

a=1 b=2 ab=53 交流=79.

我相信这是正确的。

但是,我在尝试解码时遇到问题。这是我最好的尝试,但没有成功。我相信我需要使用 pow(26,position) 并从字符串末尾递减,但我只是在努力实现这一点。这是一些可行的独立代码,但做了错误的事情:

#include <iostream>
#include <inttypes.h>
#include <string.h>
 
typedef uint32_t word_key_t;
const int CHARS_IN_ALPHABET = 26;
const int BUFFER_SIZE = 255; //ignore this for now.
 
using namespace std;
 
string reverseKey(const word_key_t key); //broken algo
 
int main(int argc, char** argv) {
        reverseKey(53); // 53 = ab
        return 0;
}
 
//disassemble a word_key_t into it's original string. returns lowercase only
string reverseKey(const word_key_t key)
{
   
  char chr, buffer[BUFFER_SIZE];
  word_key_t keyc = key, isolated, pos = BUFFER_SIZE;
 
  cout << "key: " << keyc << endl;
  
  while (keyc != 0) {
      isolated = (keyc - 1) % ((word_key_t)CHARS_IN_ALPHABET + 1);
      cout << "key: " << keyc << ", isolated: " << isolated << endl;
      chr = (char)'a' + isolated - 1;
      cout << "isolated character: " << chr << endl;
      keyc = (keyc - isolated) / CHARS_IN_ALPHABET;
      cout << "new key: " << keyc << endl;
      pos++;
  }
 
  string s("test");
  return s;
 
}

如果有人可以推动我找到正确的伪代码来解决这个问题,我将非常感激。我有点疯狂,失去了解决方案的情节。我就是看不到。有些东西告诉我 2logX / 2log26,我想我只需要一些更聪明的眼睛来关注它。然后我就可以回去学习 C++ 了。

c++ algorithm math equation-solving
5个回答
2
投票

稍后进行一些编辑。我确实误解了关键值的生成。我认为从钥匙生成字母将是:

while ( key )
   {
   int char_key = key % 26;
   char c = 'a' + (char)( char_key - 1 );
   key /= CHARS_IN_ALPHABET;      
   }

虽然我仍然不认为原来的密钥计算是正确的。我仍然认为关键计算应该是:

key = CHARS_IN_ALPHABET * key + char_key + 1;

以相反的顺序处理

raw[]
数组,以避免以相反的顺序提取它们。


1
投票

您实际上有一个以 27 为基数的数字 (aa = a*26 + b),但避免使用“零”。

INPUT:编码的Word,使得“aa”= 27,“ab”= 28等。
输出:ASCII 字符串

输出字符串 := ""
当编码Word > 0 时
  最后一个字母 = 编码字 % 27;
  编码字 = 编码字 / 27;
  outString := toChar(lastLetter + 64) + outString;
结束时
返回输出字符串;

0
投票

您的问题实际上恢复到基数到基数的转换,在您的例子中是从基数 10 到基数 26。 区别在于 a=0、b=1 等等(0=第一个符号)。

另一件事是你没有恢复转换后的字符串(ba = 53)。

这是完整的代码(第一个元素是 0,而不是 1,即 a=0)

就像在您的代码中一样,转换后的字符串中的字符不会反转(就像它们应该在正常的基数到基数转换中一样)

#include <stdio.h>
int power(int x, int times){
    int result = 1;
    while (times--) result *= x;
    return result;
}
void convert(int n, char *s){
    int i = 0;
    do {
        s[i++] = (n % 26) + 'a';
    } while ((n /= 26) > 0);
    s[i] = 0;
}
int convertBack(char *s){
    int i = 0;
    int n = 0;
    while (s[i]) {
        n += ( (s[i]-'a') * power(26, i));
        i++;
    }
    return n;
}
void main(){
    char s[100];
    convert(53, s);
    printf("Converted:%s\n",s);
    printf("Convert back=%d", convertBack(s));
}

0
投票

我建议不要使用任何“幂”函数,特别是浮点函数。

以下设置 'a' = 0、'z' = 25、'aa' = 26 等,并且仅使用整数加法、乘法和除法(无浮点)。每个编码的字符只需要一次乘法,每个解码的字符只需要一次除法。

#include <cctype>
#include <iostream>
#include <string>
#include <algorithm>

template <class T>
T encode(const char* s)
{
  T result = 0;
  while (*s != 0)
  {
    result *= 26;
    result += std::tolower(*s) - 'a';
    ++s;
  }
  return result;
}

template <class T>
std::string decode(T x)
{
  std::string s;
  while (x != 0)
  {
    s += x % 26 + 'a';
    x /= 26;
  }
  std::reverse(s.begin(), s.end());
  return s;
}

int main() 
{
  std::cout << decode(encode<unsigned int>("tbce")) << std::endl;
}

Ideone 代码在这里


0
投票

您可以权衡使用稍微多一点的空间,并通过将基数设置为 2 的幂(在您的例子中为 32)来获得更好的执行时间。

这样您就可以使用移位和逻辑运算来代替乘法、除法和取模。

例如:

void convert(int n, char *s){
    int i = 0;
    do {
        s[i++] = (n && 0x1F) + 'a';
    } while ((n >>= 5) > 0);
    s[i] = 0;
}

int convertBack(char *s){
    int i = 0;
    int n = 0;
    while (s[i]) {
        n += ( (s[i]-'a') >> 5*i;
        i++;
    }
    return n;
}

主要内容应该与kcsoft建议的相同。

© www.soinside.com 2019 - 2024. All rights reserved.