LeetCode 535. Encode and Decode TinyURL (java)

题目:

TinyURL is a URL shortening service where you enter a URL such as “https://leetcode.com/problems/design-tinyurl” and it returns a short URL such as “http://tinyurl.com/4e9iAk“.

Design the encode and decode methods for the TinyURL service. There is no restriction on how your encode/decode algorithm should work. You just need to ensure that a URL can be encoded to a tiny URL and the tiny URL can be decoded to the original URL.

解法一:我的解法

我们需要将原来的网址String s用一串符号String result代替,encode的时候把设计好的result和s放进hashmap中, 然后变成“http://tinyurl.com/result”的短url,这样在decode的时候就可以直接通过result在hashmap中获取原来String s的地址。那么重点在于我们如果对s得到result的字符串。下面的代码是我的方法,每次都随机从s中挑选三个字符,再加上从Integer.MIN_VALUE开始到Integer.MAX_VALUE的一个数字,这样的好处是:1. 可以保证hashmap里的key不会重复,因为每个字符串都有一个不同的数字,并且这个short url不会被预测,LeetCode的solution里有一个直接用0~(2^32-1)的数字进行编码的答案,虽然简单易行,但是非常容易被人猜到下一个url或者是获取所有的url。2. 操作简单,代码很短。局限:1. 最多只能解决(2^32 )个url地址,如果overflow的话,会覆盖之前的url,造成数据损失。2. shorten之后的short url长度并不一定会比原url短,取决于出现的顺序,result的长度为4~13位不等。

Java 代码:

public class Codec {
    HashMap<String,String> map = new HashMap<>();
    Random rand = new Random();
    int index = Integer.MIN_VALUE;

    // Encodes a URL to a shortened URL.
    public String encode(String longUrl) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 3; i++) {
            sb.append(longUrl.charAt(rand.nextInt(longUrl.length())));
        }
        sb.append(index++);
        map.put(sb.toString(), longUrl);
        return "http://tinyurl.com/" + sb.toString();
    } 

    // Decodes a shortened URL to its original URL.
    public String decode(String shortUrl) {
        return map.get(shortUrl.replace("http://tinyurl.com/",""));
    }
}

解法二:用定长编码来解

好处: 1. 每次的result都是n位的,同时能代表的url个数是62^n, 并且tiny url是不可预测的。

代码:(n=6)


public class Codec {
    String alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    HashMap<String, String> map = new HashMap<>();
    Random rand = new Random();
    String key = getRand();

    public String getRand() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            sb.append(alphabet.charAt(rand.nextInt(62)));
        }
        return sb.toString();
    }

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

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

解法三:hashCode()

直接用系统的longUrl.hashCode()函数作为result,缺点是会出现hash collision, 正如生日悖论(birthday paradox)那样。当有100,000个object出现后,collision的概率就会达到50%。

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/", "")));
    }
}

同理,用random()来产生随机数的方法和hashcode一样,可能会出现collision,如果url数量不大的话,这两种也是可行的方案。

阅读更多
文章标签: leetcode java
个人分类: system design fb
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭