Medium
题目描述
注意:这是系统设计问题:设计 TinyURL 的配套问题。
TinyURL 是一种 URL 缩短服务,您可以在其中输入 URL(例如 https://leetcode.com/problems/design-tinyurl),它会返回一个短 URL(例如 http://tinyurl.com/4e9iAk)。设计一个类来编码 URL 和解码短 URL。
对于您的编码/解码算法如何工作没有限制。您只需要确保一个 URL 可以被编码为短 URL,并且短 URL 可以被解码为原始 URL。
实现 Solution 类:
Solution()初始化系统对象。String encode(String longUrl)为给定的longUrl返回一个短 URL。String decode(String shortUrl)为给定的shortUrl返回原始长 URL。保证给定的shortUrl是由同一个对象编码的。
示例 1:
输入:url = "https://leetcode.com/problems/design-tinyurl"
输出:"https://leetcode.com/problems/design-tinyurl"
解释:
Solution obj = new Solution();
string tiny = obj.encode(url); // 返回编码的短 url
string ans = obj.decode(tiny); // 返回解码后的原始 url
约束条件:
1 <= url.length <= 10^4url保证是一个有效的 URL。
解题思路
这个问题有多种解法思路:
方法一:基于计数器的简单编码 使用一个递增的计数器为每个长 URL 分配一个唯一的数字 ID,然后将这个 ID 作为短 URL 的后缀。这种方法简单高效,编码后的 URL 长度较短。
方法二:基于哈希的编码 使用哈希函数(如 MD5 或 SHA)对长 URL 进行哈希,取哈希值的前几位作为短 URL 的标识符。需要处理哈希冲突问题。
方法三:随机字符串生成 为每个长 URL 生成一个随机的字符串作为短 URL 标识符,需要确保不会产生重复。
本题解采用方法一(推荐),因为它实现简单、性能好,且在实际场景中很实用。我们维护两个哈希表:一个用于从长 URL 到短 URL 的映射,另一个用于从短 URL 到长 URL 的反向映射。使用递增计数器确保每个短 URL 都是唯一的。
这种方法的优点是:
- 编码速度快,时间复杂度 O(1)
- 生成的短 URL 长度短且规律
- 不存在冲突问题
- 易于实现和维护
代码实现
class Solution {
private:
unordered_map<string, string> longToShort;
unordered_map<string, string> shortToLong;
int counter;
string baseUrl = "http://tinyurl.com/";
public:
Solution() : counter(0) {}
// Encodes a URL to a shortened URL.
string encode(string longUrl) {
if (longToShort.find(longUrl) != longToShort.end()) {
return longToShort[longUrl];
}
string shortUrl = baseUrl + to_string(counter++);
longToShort[longUrl] = shortUrl;
shortToLong[shortUrl] = longUrl;
return shortUrl;
}
// Decodes a shortened URL to its original URL.
string decode(string shortUrl) {
return shortToLong[shortUrl];
}
};
class Codec:
def __init__(self):
self.long_to_short = {}
self.short_to_long = {}
self.counter = 0
self.base_url = "http://tinyurl.com/"
def encode(self, longUrl: str) -> str:
"""Encodes a URL to a shortened URL.
"""
if longUrl in self.long_to_short:
return self.long_to_short[longUrl]
short_url = self.base_url + str(self.counter)
self.counter += 1
self.long_to_short[longUrl] = short_url
self.short_to_long[short_url] = longUrl
return short_url
def decode(self, shortUrl: str) -> str:
"""Decodes a shortened URL to its original URL.
"""
return self.short_to_long[shortUrl]
public class Codec {
private Dictionary<string, string> longToShort;
private Dictionary<string, string> shortToLong;
private int counter;
private string baseUrl = "http://tinyurl.com/";
public Codec() {
longToShort = new Dictionary<string, string>();
shortToLong = new Dictionary<string, string>();
counter = 0;
}
// Encodes a URL to a shortened URL
public string encode(string longUrl) {
if (longToShort.ContainsKey(longUrl)) {
return longToShort[longUrl];
}
string shortUrl = baseUrl + counter.ToString();
counter++;
longToShort[longUrl] = shortUrl;
shortToLong[shortUrl] = longUrl;
return shortUrl;
}
// Decodes a shortened URL to its original URL.
public string decode(string shortUrl) {
return shortToLong[shortUrl];
}
}
var counter = 0;
var longToShort = new Map();
var shortToLong = new Map();
var baseUrl = "http://tinyurl.com/";
/**
* Encodes a URL to a shortened URL.
*
* @param {string} longUrl
* @return {string}
*/
var encode = function(longUrl) {
if (longToShort.has(longUrl)) {
return longToShort.get(longUrl);
}
var shortUrl = baseUrl + counter.toString();
counter++;
longToShort.set(longUrl, shortUrl);
shortToLong.set(shortUrl, longUrl);
return shortUrl;
};
/**
* Decodes a shortened URL to its original URL.
*
* @param {string} shortUrl
* @return {string}
*/
var decode = function(shortUrl) {
return shortToLong.get(shortUrl);
};
复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| encode | O(1) | O(n) |
| decode | O(1) | O(n) |
其中 n 是已编码的 URL 数量。空间复杂度主要用于存储两个哈希表的映射关系。