Problem

Note: This is a companion problem to the System Design problem: Design TinyURL.

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 a class to encode a URL and decode a tiny URL.

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.

Implement the Solution class:

  • Solution() Initializes the object of the system.
  • String encode(String longUrl) Returns a tiny URL for the given longUrl.
  • String decode(String shortUrl) Returns the original long URL for the given shortUrl. It is guaranteed that the given shortUrl was encoded by the same object.

Examples

Example 1:

Input: url = "https://leetcode.com/problems/design-tinyurl"
Output: "https://leetcode.com/problems/design-tinyurl"

Explanation:
Solution obj = new Solution();
string tiny = obj.encode(url); // returns the encoded tiny url.
string ans = obj.decode(tiny); // returns the original url after deconding it.

Solution

Method 1 - Using Linked List

We can store the urls in the ArrayList, and return the index at which it is stored.

Code

Java
public class Codec {
    private final List<String> list = new ArrayList<>();
	private static final String BASE_HOST = "http://tinyurl.com/";
    // Encodes a URL to a shortened URL.
    public String encode(String longUrl) {
        list.add(longUrl);
        return BASE_HOST.concat(String.valueOf(list.size()));
    }

    // Decodes a shortened URL to its original URL.
    public String decode(String shortUrl) {
        String[] parts = shortUrl.split(BASE_HOST);
        String code = parts[1];
        return list.get(Integer.parseInt(code) - 1);
    }
}

Complexity

  • ⏰ Time complexity: O(1) for both encoding and decoding.
  • 🧺 Space complexity: O(n*l) for n urls with average length l.

Method 2 - Using Hashmap

What if we want fixed length url, then this method can help. So, we do following

  1. Use index to map generated short url to long url
  2. Use revIndex to map long url to short url (We can also use set here, but can help if we need to extend the problem)
  3. We use do while loop to generate 6 digit random string, so that we enter the loop at-least once. We will just generate the short url or key. If it is already present in index, we will try again, till we find a new key which is not yet present in index. This avoids collisions.
  4. Now, we are out loop, we save this generated key or shortUrl to index and reverse mapping to revIndex.

Code

Java
public class Codec {
    Map<String, String> index = new HashMap<String, String>();
    Map<String, String> revIndex = new HashMap<String, String>();
    static String BASE_HOST = "http://tinyurl.com/";
    
    // Encodes a URL to a shortened URL.
    public String encode(String longUrl) {
        if (revIndex.containsKey(longUrl)) return BASE_HOST + revIndex.get(longUrl);
        String charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String key = null;
        do {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 6; i++) {
                int r = (int) (Math.random() * charSet.length());
                sb.append(charSet.charAt(r));
            }
            key = sb.toString();
        } while (index.containsKey(key));
        index.put(key, longUrl);
        revIndex.put(longUrl, key);
        return BASE_HOST + key;
    }

    // Decodes a shortened URL to its original URL.
    public String decode(String shortUrl) {
        return index.get(shortUrl.replace(BASE_HOST, ""));
    }
}