Skip to main content

535. Encode and Decode TinyURL

Question

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

Constraints:

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

Approach

  1. longToShort provides the map to retrieve encoded URL using long URL. shortToLong does the opposite.
  2. baseUrl is the prefix we return each time after encoding.
  3. usableStr are the available characters we generate as the suffix of URL.

Encode

  1. First, check if the key longUrl already exists. If yes, return with prefix.
  2. If no, we need to do the actual encoding.
  3. Generate a len 6 string from our usableStr, and check if this suffix exists in shortToLong. If yes, re-generate until it is a new string.
  4. Save the pre-encoded and encoded URLs into both maps, and return encoded URL with prefix.

Decode

  1. Retrieve from shortToLong map with the key shortUrl (Only the last 6 characters, i.e. the encoded string suffix).

Solution

class Solution {
public:

string usableStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
unordered_map<string, string> longToShort, shortToLong;
string baseUrl = "http://tinyurl.com/";

// Encodes a URL to a shortened URL.
string encode(string longUrl) {
if (longToShort.count(longUrl)) return baseUrl + longToShort[longUrl];

string encoded;

while(true){
encoded.clear();
//Encoded code is 6 chars
for(int i = 0; i < 6; i++){
encoded += usableStr[rand()%62];
}

if(!shortToLong.count(encoded)) break;
}

longToShort[longUrl] = encoded;
shortToLong[encoded] = longUrl;

return baseUrl + encoded;
}

// Decodes a shortened URL to its original URL.
string decode(string shortUrl) {
return shortToLong[shortUrl.substr(shortUrl.size() - 6)];
}
};
type Codec struct {
longToShort map[string]string
shortToLong map[string]string
baseUrl string
usableStr string
}

func Constructor() Codec {
var c Codec
c.baseUrl = "http://tinyurl.com/"
c.usableStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
c.longToShort = make(map[string]string)
c.shortToLong = make(map[string]string)
return c
}

// Encodes a URL to a shortened URL.
func (this *Codec) encode(longUrl string) string {
_, isIn := this.longToShort[longUrl]

if isIn{
return this.baseUrl + this.longToShort[longUrl]
}

var encoded string
usableStrRune := []rune(this.usableStr)

for {
encoded = "";

for i:= 0; i < 6; i++{
encoded += string(usableStrRune[rand.Intn(1000) % 62])
}

_, isIn := this.shortToLong[encoded]

if !isIn {
break;
}
}

this.longToShort[longUrl] = encoded
this.shortToLong[encoded] = longUrl

return this.baseUrl + encoded
}

// Decodes a shortened URL to its original URL.
func (this *Codec) decode(shortUrl string) string {
shortUrlRune := []rune(shortUrl)
return this.shortToLong[string(shortUrlRune[len(shortUrlRune) - 6:])]
}