从给定的编码ascii字符串解码所有可能性

时间:2018-04-10 04:19:23

标签: java python ascii

通过执行以下一系列动作对字符串进行编码:
1.用ASCII值表示替换每个字符 2.翻转字符串。

例如,下表显示了字符串的转换 "HelloWorld"到ASCII字符串"7210110810811187111114108100"

字符

H  e   l   l   o    W  o   r   l   d

ASCII值

72 101 108 108 111  87 111 114 108 100

然后反转ASCII字符串以获取编码字符串"0018014111117811180180110127“。

编码字符串中的字符在10 - 126范围内,包括特殊字符。

我需要编写一个必须解码编码字符串的函数和返回可以解码的方法列表。

我无法解决这个问题。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:2)

solutions = []
currentSolution = ''
unprocessed = ''


def decode(s):
    flipped = s[::-1]
    global solutions
    global unprocessed
    global currentSolution
    currentSolution = ''
    unprocessed = flipped
    _decode()
    return solutions


def is_valid(split):
    if split.startswith('0'):
        return False
    value = int(split)
    if value < 10 or value > 126:
        return False
    return True


def _decode():
    global unprocessed
    global currentSolution
    global solutions
    if len(unprocessed) == 0:
        solutions.append(currentSolution)
    else:
        possible_splits = list()
        possible_splits.append(unprocessed[0:2])
        possible_splits.append(unprocessed[0:3])

        for split in possible_splits:
            if is_valid(split):
                decoded_character = chr(int(split))
                currentSolution += decoded_character
                unprocessed = unprocessed[len(split):]
                _decode()
                currentSolution = currentSolution[0: len(currentSolution) - 1]
                unprocessed = split + unprocessed


def main():
    final_solutions = decode('0018014111117811180180110127')
    print(final_solutions)


if __name__ == '__main__':
    main()

答案 1 :(得分:1)

我想指出你在问一个非常重要的计算机科学问题 - 我在一个介绍数据结构/算法类中看到了这个问题。我假设你知道我将在这里使用的一些术语。

我使用backtracking计算每个可能的拆分,如果拆分有效(例如使用了所有数字),那么我将其添加到解决方案列表中。

您会注意到它不是最有效的算法,但它仍适用于您的输入。我相信时间复杂度类似于O(2^n)(尽管我可能错了)因为@Mulliganaceous指出,在每个决定拆分时,你创建另一个分支,最多有两个选项。

此外,由于您需要所有可能的方法,因此您需要耗尽此搜索树,直至找到所有解决方案。您可以使用dynamic programming获得更快的算法,但我还没有考虑过这个问题。

所以这里是O(2^n)解决方案:

以下代码在评论中包含以下步骤。

  1. 初始一些状态。你需要:
    1. 一个空的解决方案列表
    2. 正在考虑的当前解决方案
    3. 当前未处理的子字符串
  2. 使用初始decode函数/方法启动回溯。在此方法中,翻转输入并将其分配给未处理的子字符串。如果您计划多次运行此功能,还可以重置其他状态参数。调用递归_decode函数来启动回溯。
  3. 在回溯方法中,检查是否找到了解决方案(未处理的字符串为空时的基本情况)。如果已找到,请将当前解决方案添加到解决方案列表中
  4. 解决方案检查后,
  5. 生成当前未处理字符串的所有可能拆分列表。例如:让我们说未处理的字符串是123456。对于此字符串,此分支只有2个可能的拆分:12123。如果未处理的字符串仅为78,则只有一种可能的分割:78
  6. 遍历隐式搜索树的当前分支的可能拆分列表。检查拆分是否有效。在这种情况下,如果解析后的字符串作为数字介于10和126之间,则您的要求表示拆分有效。此外,具有拆分的字符串不能以零开头,因为当最初创建字符串时,不可能填充零。
  7. 如果拆分有效,则更改状态。在这种情况下,将解码后的字符添加到解决方案中并从未处理的字符串中删除拆分(因为您已对其进行处理)
  8. 更深入。递归调用_decode方法。这将继续沿着搜索树向下,直到它没有任何选项。
  9. 回溯。一旦callstack从这个电话回来,这意味着它没有找到任何选项。你必须撤消你在它上面设置的状态。在这种情况下,从当前解决方案中删除该字符,并将拆分添加回未处理的字符串。
  10. 那就是那个!

    但是这里有一些javascript代码(javascript中的唯一原因是你可以按下&#34;运行代码片段&#34;浏览器中的按钮)。

    如果您使用的是mac,请点击Cmd + option I,然后点击&#34;运行代码段&#34; 如果您使用的是Windows F12,然后点击“#34;运行代码段&#34;

    您将看到您的浏览器打开调试器。 单步执行代码。看看它在做什么。

    &#13;
    &#13;
    // 1
    let solutions = [];
    let currentSolution = '';
    let unprocessed = '';
    
    function range(n) {
      const list = [];
      for (let i = 0; i < n; i += 1) {
        list.push(i);
      }
      return list;
    }
    
    // 2
    function decode(input) {
      const flipped = input
        .split('')
        .reverse()
        .join('');
    
      solutions = [];
      currentSolution = '';
      unprocessed = flipped;
    
      _decode();
    
      return solutions.slice();
    }
    
    function isValid(split) {
      if (split.startsWith('0')) return false;
      const value = parseInt(split, 10);
      if (value < 10) return false;
      if (value > 126) return false;
      return true;
    }
    
    function _decode() {
      // 3
      if (unprocessed.length === 0) {
        solutions.push(currentSolution);
      }
      // 4
      const possibleSplits = range(2)
        .map(i => i + 1)
        .filter(i => i < unprocessed.length)
        .map(i => unprocessed.substring(0, i + 1));
    
      // 5
      for (const split of possibleSplits) {
        if (isValid(split)) {
          const decodedCharacter = String.fromCharCode(parseInt(split, 10));
          // 6
          currentSolution += decodedCharacter;
          unprocessed = unprocessed.substring(split.length);
          // 7
          _decode();
          // 8
          currentSolution = currentSolution.substring(0, currentSolution.length - 1);
          unprocessed = split + unprocessed;
        }
      }
    }
    
    debugger;
    console.time('calculation time');
    const finalSolutions = decode('0018014111117811180180110127');
    console.timeEnd('calculation time');
    console.log(finalSolutions.length, 'solutions (all but one of them contain special characters)');
    console.log(finalSolutions);
    
    console.log('final solutions in ascii code');
    console.log(finalSolutions
      .map(solution => solution
        .split('')
        .map(c => c.charCodeAt(0))
        .map(code => code.toString())
        .join(', ')
      )
      .map(line => `[${line}]`)
      .join('\n')
    )
    &#13;
    &#13;
    &#13;

      

    您是否还可以在代码中添加一个附加部分,将每个字符打印为ASCII代码,每个字符都用括号括起来? - Mulliganaceous 24分钟前

    肯定的是,看到编辑过的答案。

    编辑:更新isValid函数以检查字符串是否以0开头,如果是,则不应认为该分割有效。