加密和解码(不同加密方法:随机数,hash,出现次数)

原题:

TinyURL是一种URL简化服务, 比如:当你输入一个URL https://leetcode.com/problems/design-tinyurl 时,它将返回一个简化的URL http://tinyurl.com/4e9iAk.

要求:设计一个 TinyURL 的加密 encode 和解密 decode 的方法。你的加密和解密算法如何设计和运作是没有限制的,你只需要保证一个URL可以被加密成一个TinyURL,并且这个TinyURL可以用解密方法恢复成原本的URL。

解法:

随机数
大致框架:
# # class Codec:

#     def encode(self, longUrl: str) -> str:
#         """Encodes a URL to a shortened URL.
#         """
#     def decode(self, shortUrl: str) -> str:
#         """Decodes a shortened URL to its original URL.
#         """
代码:
import random
class Codec:
    
    """
    URL简化类:将一个长url转化为一个短url(转换后的 URL路径 为6位数的字母或数字)
    转化算法:使用 62 位由大小写字母和数字构成的字符串集合 作为 【62进制位表】,
            可表示的 6位url 数量为 62 ** 6 == 586亿多,几亿次以内的调用不用担心
            字典键冲突,不够用的话可以再增加进制位数。

    """
    _chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
    _dict = {}
    _key = ''.join(random.sample(_chars, 6))

    @classmethod
    def get_rand(cls):
        return ''.join(random.sample(cls._chars, 6))

    @classmethod
    def encode(cls, long_url):
        """
        将一个 长URL 编码为一个 短URL【随机固定长度加密】。
        使用 random 模块 随机从 62 位字符串中选取 6 个作为 URL短路径。
        因为使用了随机数,根据 short_url 来预测字典大小几乎是不可能的,数据更加安全。
        """
        while cls._dict.get(cls._key):
            cls._key = cls.get_rand()

        cls._dict[cls._key] = long_url
        return 'http://tinyurl.com/' + cls._key

    @classmethod
    def decode(cls, short_url):
        """
        将一个 短URL 解码为一个 长URL。
        直接根据 url字符串后6位,从字典中取值。
        """
        return cls._dict[short_url[19:]]

# Your Codec object will be instantiated and called as such:
# codec = Codec()
# codec.decode(codec.encode(url))
使用简单的计数 [Accepted]

为了加密 URL,我们使用计数器 ( i ) (i) (i) ,每遇到一个新的 URL 都加一。我们将 URL 与它的次数 i i i 放在哈希表 HashMap 中,这样我们在稍后的解密中可以轻易地获得原本的 URL。

public class Codec {
    Map<Integer, String> map = new HashMap<>();
    int i = 0;

    public String encode(String longUrl) {
        map.put(i, longUrl);
        return "http://tinyurl.com/" + i++;
    }

    public String decode(String shortUrl) {
        return map.get(Integer.parseInt(shortUrl.replace("http://tinyurl.com/", "")));
    }
}

分析:

可以加密解密的 URL 数目受限于int 所能表示的范围。

如果超过int 个 URL 需要被加密,那么超过范围的整数会覆盖之前存储的 URL,导致算法失效。

URL 的长度不一定比输入的 longURL 短。它只与加密的 URL 被加密的顺序有关。

这个方法的问题是预测下一个会产生的加密 URL 非常容易,因为产生几个 URL 后很容易推测出生成的模式。

使用出现次序加密

这种方法中,我们将当前 URL 第几个出现作为关键字进行加密,将这个出现次序看做 62 进制,并将每一位映射到一个长度为 62 位的表中对应的字母作为哈希值。此方法中,我们使用一系列整数和字母表来加密,而不是仅仅使用数字进行加密。

public class Codec {

    String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    HashMap<String, String> map = new HashMap<>();
    int count = 1;

    public String getString() {
        int c = count;
        StringBuilder sb = new StringBuilder();
        while (c > 0) {
            c--;
            sb.append(chars.charAt(c % 62));
            c /= 62;
        }
        return sb.toString();
    }

    public String encode(String longUrl) {
        String key = getString();
        map.put(key, longUrl);
        return "http://tinyurl.com/" + key;
        count++;
    }

    public String decode(String shortUrl) {
        return map.get(shortUrl.replace("http://tinyurl.com/", ""));
    }
}

分析:

可加密的 URL 数目还是依赖于 int 的范围。因为相同的 countcount 在出现次序溢出整数范围后仍然会出现。

加密后 URL 的长度不一定更短,但某种程度上与 longURL 的出现次序相对独立。比方说产生的 URL
长度按顺序会是 1(62次),2(62次)。

这个算法的表现比较好,因为相同的加密结果只有在溢出整数后才会发生,这个范围非常大。

如果出现重复,下一次产生的加密结果还是能通过某种计算被预测出来。

hashcode 在这里插入图片描述
public class Codec {
    Map<Integer, String> map = new HashMap<>();

    public String encode(String longUrl) {
        map.put(longUrl.hashCode(), longUrl);
        return "http://tinyurl.com/" + longUrl.hashCode();
    }

    public String decode(String shortUrl) {
        return map.get(Integer.parseInt(shortUrl.replace("http://tinyurl.com/", "")));
    }
}

分析

可加密 URL 的数目由int 决定,因为hashCode 使用整数运算。

加密后 URL 的平均长度与 \text{longURL}longURL 的长度没有直接关联。

hashCode() 对于不同的字符串不一定产生独一无二的加密后
URL。像这样对于不同输入产生相同输出的过程叫做冲突。因此,如果加密字符串的数目增加,冲突的概率也会增加,最终导致算法失效。

下图展示了不同对象映射到相同的 hashcode,以及对象越多冲突概率越大。在这里插入图片描述
可能几个字符串加密后冲突就会发生,会远比 \text{int}int 要小。这与生日悖论类似,也就是如果有23个人,存在 2 个人同一天生日的概率达到 50%,如果有 70 个人,这一概率会高达 99.9%。

这种方法中,很难根据前面产生的 URL 结果预测后面加密 URL 的答案。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值