leetcode 2227 — 加密解密字符串

leetcode 2227 — 加密解密字符串

一、题目描述

在这里插入图片描述

二、算法

这道题使用逆向分析比较简单,我们这里主要是学习下字典树的使用。

1、字典树

字典树(trie),其实就是一个有限状态自动机。一个由 aanthe 三个单词构成的字典树如图:
在这里插入图片描述
通常,我们可以使用状态转移矩阵来保存转换过程:

class Trie {
	static const int MAX_STATUS_NUM = 100000;
	int statusNum = 0;
	int fsm[MAX_STATUS_NUM][26] = { 0 };
	int accept[MAX_STATUS_NUM] = { 0 };

public:
	void insert(const char* s, int len) {
		int status = 0;
		for (int i = 0; i < len; ++i) {
			int index = s[i] - 'a';

			if (fsm[status][index] == 0) {
				fsm[status][index] = ++statusNum;
			}

			status = fsm[status][index];
		}

		accept[status] = true;
	}

	bool find(const char* s, int len) {
		int status = 0;
		for (int i = 0; i < len; ++i) {
			int index = s[i] - 'a';

			if (fsm[status][index] == 0) {
				return false;
			}

			status = fsm[status][index];
		}

		return accept[status];
	}
};

2、实现

这里加密的过程就不说了。解密需要保存所有密文对应的明文。如果节约空间,首选应该是 unordered_multimap。不过,使用这个数据结构在查找时需要耗费一定的时间,算法很容易超时。考虑到每个密文都由两个字符组成,我们使用 26*26 的数组来保存。另外,由于解密是逐字符解密。我们选择使用递归来求解明文字符串个数:

class Encrypter {
	...

	int find(char* s, int l, int start = 0) {
		if (l == 0) {
			return accept[start] ? 1 : 0;
		}
		else if ((l & 0x1) == 1) {
			return 0;
		}

		int ret = 0;
		for (auto& ch : vk[s[0] - 'a'][s[1] - 'a']) {
			int c = ch - 'a';
			if (fsm[start][c] != 0) {
				ret += find(s + 2, l - 2, fsm[start][c]);
			}
		}

		return ret;
	}

	vector<vector<vector<char>>> vk;
public:
	Encrypter(vector<char>& keys, vector<string>& values, vector<string>& dictionary) :
		vk(26, vector<vector<char>>(26))
	{
		for (auto &word : dictionary) {
			insert((char*)word.c_str(), word.length());
		}

		for (int i = 0; i < keys.size(); ++i) {
			vk[values[i][0] - 'a'][values[i][1] - 'a'].push_back(keys[i]);
		}
	}

	int decrypt(string word2) {
		return find((char*)word2.c_str(), word2.length());
	}
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值