{x}
blog image

Encode and Decode TinyURL

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.

 

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 decoding it.

 

Constraints:

  • 1 <= url.length <= 104
  • url is guranteed to be a valid URL.

Solution Explanation for Encode and Decode TinyURL

This problem requires designing a URL shortening service similar to TinyURL. The core idea is to map long URLs to short, unique identifiers and vice-versa. This solution utilizes a hash map (dictionary in Python) to store the mapping between long and short URLs.

Approach

  1. Encoding: A long URL is provided as input. We generate a unique short code (in this case, an incrementing integer) and store it as a key in the hash map, with the long URL as the value. The short URL is constructed by concatenating a base domain ("https://tinyurl.com/") with the generated short code.

  2. Decoding: A short URL is given. We extract the short code from the URL (by removing the base domain). We use this code to look up the corresponding long URL in the hash map and return it.

Code Explanation (Python)

class Codec:
    def __init__(self):
        self.m = defaultdict() #Hashmap to store mappings; defaultdict handles missing keys gracefully
        self.idx = 0 #counter for unique short codes
        self.domain = 'https://tinyurl.com/' #base URL
 
    def encode(self, longUrl: str) -> str:
        self.idx += 1
        self.m[str(self.idx)] = longUrl #store long url with index as key
        return f'{self.domain}{self.idx}' #construct short url
 
    def decode(self, shortUrl: str) -> str:
        idx = shortUrl.split('/')[-1] #extract short code from url
        return self.m[idx] #retrieve long url using short code
 

The Python solution uses defaultdict from the collections module. defaultdict avoids KeyError exceptions when trying to access a non-existent key. If a key is not present, it automatically creates an entry with a default value.

Code Explanation (Java)

public class Codec {
    private Map<String, String> m = new HashMap<>(); //HashMap for url mappings
    private int idx = 0; //counter for unique codes
    private String domain = "https://tinyurl.com/"; //base url
 
    public String encode(String longUrl) {
        String v = String.valueOf(++idx); //generate unique code
        m.put(v, longUrl); //add to HashMap
        return domain + v; //create short url
    }
 
    public String decode(String shortUrl) {
        int i = shortUrl.lastIndexOf('/') + 1; //find last '/' to extract code
        return m.get(shortUrl.substring(i)); // retrieve long url
    }
}

The Java code uses HashMap for the mapping. The lastIndexOf('/') method efficiently finds the index of the last occurrence of '/'.

Time and Space Complexity

Time Complexity:

  • encode(): O(1) - Encoding involves constant-time operations (incrementing idx, adding to the hash map).
  • decode(): O(1) - Decoding involves constant-time operations (extracting the code, looking up in the hash map).

Space Complexity:

  • O(N), where N is the number of encoded URLs. The space used grows linearly with the number of URL mappings stored in the hash map.

Improvements and Considerations

  • Collision Handling: This solution uses incrementing integers as short codes. For a truly robust system, a more sophisticated approach might be needed to handle potential collisions (two different long URLs accidentally generating the same short code). Hash functions with collision resolution strategies could be used.
  • Database Persistence: For a real-world TinyURL system, data persistence is crucial. The hash map should be backed by a database (like Redis or MySQL) to survive application restarts and handle a large number of URLs.
  • Base62 Encoding: Instead of using integers, using base62 encoding (0-9, a-z, A-Z) would result in shorter codes.
  • Error Handling: More robust error handling could be added (e.g., handling invalid short URLs).

This explanation provides a clear understanding of the core algorithm and implementation details. The provided code is functional but could be enhanced for robustness and scalability in a production environment.