|
2 | 2 |
|
3 | 3 | import java.util.HashMap;
|
4 | 4 | import java.util.Map;
|
| 5 | +import java.util.Random; |
5 | 6 |
|
6 | 7 | /**
|
| 8 | + * 535. Encode and Decode TinyURL |
| 9 | + * |
7 | 10 | * TinyURL is a URL shortening service where you enter a URL such as https://leetcode.com/problems/design-tinyurl
|
8 | 11 | * and it returns a short URL such as http://tinyurl.com/4e9iAk.
|
9 | 12 | * Design the encode and decode methods for the TinyURL service.
|
|
12 | 15 |
|
13 | 16 | Note: Do not use class member/global/static variables to store states. Your encode and decode algorithms should be stateless.
|
14 | 17 | */
|
| 18 | + |
15 | 19 | public class _535 {
|
16 |
| - public class Codec { |
17 |
| - Map<String, Long> map = new HashMap<>(); |
18 |
| - Long maxValue = 0L; |
19 |
| - Map<Long, String> reverseMap = new HashMap<>(); |
| 20 | + |
| 21 | + public static class Solution1 { |
| 22 | + /** |
| 23 | + * Simple counter approach |
| 24 | + * Analysis: |
| 25 | + * The range of URLs that can be decoded is limited by the range of Integer. |
| 26 | + * If excessively large number of URLs have to be encoded, after the range of Integer is exceeded, |
| 27 | + * integer overflow could lead to overwriting previous URL's encodings. |
| 28 | + * The length of the URL isn't necessary shorter than incoming URL. |
| 29 | + * One potential security issue with this problem is that it's very easy to predict the next code generated, |
| 30 | + * since this pattern is very easy to be detected. |
| 31 | + */ |
| 32 | + public class Codec { |
| 33 | + int i = 0; |
| 34 | + Map<Integer, String> map = new HashMap(); |
| 35 | + public static final String PREFIX = "http://tinyurl/"; |
| 36 | + |
| 37 | + public String encode(String longUrl) { |
| 38 | + map.put(i, longUrl); |
| 39 | + return PREFIX + i++; |
| 40 | + } |
| 41 | + |
| 42 | + public String decode(String shortUrl) { |
| 43 | + return map.get(Integer.parseInt(shortUrl.substring(PREFIX.length()))); |
| 44 | + } |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + public static class Solution2 { |
| 49 | + /** |
| 50 | + * Use Java built-in HashCode |
| 51 | + * Analysis: |
| 52 | + * hashCode() does NOT generate unique codes for different strings, collision might happen. |
| 53 | + * As the number of URLs increase, the probability of getting collision increases which leads to failure. |
| 54 | + */ |
| 55 | + public class Codec { |
| 56 | + Map<Integer, String> map = new HashMap<>(); |
| 57 | + public static final String PREFIX = "http://tinyurl/"; |
| 58 | + |
| 59 | + // Encodes a URL to a shortened URL. |
| 60 | + public String encode(String longUrl) { |
| 61 | + /**I don't need to create a local variable to cache longUrl.hashCode() |
| 62 | + * since Java's String cache it already. :) Look at its source code.*/ |
| 63 | + map.put(longUrl.hashCode(), longUrl); |
| 64 | + return PREFIX + longUrl.hashCode(); |
| 65 | + } |
| 66 | + |
| 67 | + // Decodes a shortened URL to its original URL. |
| 68 | + public String decode(String shortUrl) { |
| 69 | + return map.get(Integer.parseInt(shortUrl.substring(PREFIX.length()))); |
| 70 | + } |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + public static class Solution3 { |
| 75 | + /**Use a random number*/ |
| 76 | + Map<Integer, String> map = new HashMap<>(); |
| 77 | + Random random = new Random(); |
| 78 | + public static final String PREFIX = "http://tinyurl/"; |
20 | 79 |
|
21 | 80 | // Encodes a URL to a shortened URL.
|
22 | 81 | public String encode(String longUrl) {
|
23 |
| - maxValue++; |
24 |
| - map.put(longUrl, maxValue); |
25 |
| - reverseMap.put(maxValue, longUrl); |
26 |
| - return String.valueOf(maxValue); |
| 82 | + int num = random.nextInt(Integer.MAX_VALUE); |
| 83 | + while (map.containsKey(num)) { |
| 84 | + num = random.nextInt(Integer.MAX_VALUE); |
| 85 | + } |
| 86 | + map.put(num, longUrl); |
| 87 | + return PREFIX + num; |
| 88 | + } |
| 89 | + |
| 90 | + // Decodes a shortened URL to its original URL. |
| 91 | + public String decode(String shortUrl) { |
| 92 | + return map.get(Integer.parseInt(shortUrl.substring(PREFIX.length()))); |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + public static class Solution4 { |
| 97 | + /** |
| 98 | + * Use a random but fixed length encoding |
| 99 | + * Analysis: |
| 100 | + * 1. This is the most optimal solution so far. |
| 101 | + * 2. The number of URLs that can be encoded can be as big as Math.pow((10 + 26*2), FIXED_LENGTH) |
| 102 | + * 3. The length of the shortened URL is fixed at a certain length, which could be a significant reduce for large URLs |
| 103 | + * 4. The performance of this scheme is pretty good, due to much smaller probability of encountering collision |
| 104 | + * 5. Predicting pattern/encoding isn't possible in this case since random numbers are used. |
| 105 | + */ |
| 106 | + Map<String, String> map = new HashMap<>(); |
| 107 | + public static final String PREFIX = "http://tinyurl/"; |
| 108 | + public static final int FIXED_LENGTH = 7; |
| 109 | + Random random = new Random(); |
| 110 | + String alphabet = "0123456789abcdefghijklmnopgrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| 111 | + |
| 112 | + // Encodes a URL to a shortened URL. |
| 113 | + public String encode(String longUrl) { |
| 114 | + String shortKey = getRandomFixedLengthKey(); |
| 115 | + while (map.containsKey(shortKey)) { |
| 116 | + shortKey = getRandomFixedLengthKey(); |
| 117 | + } |
| 118 | + map.put(shortKey, longUrl); |
| 119 | + return PREFIX + shortKey; |
| 120 | + } |
| 121 | + |
| 122 | + private String getRandomFixedLengthKey() { |
| 123 | + StringBuilder stringBuilder = new StringBuilder(); |
| 124 | + for (int i = 0; i < FIXED_LENGTH; i++) { |
| 125 | + stringBuilder.append(alphabet.charAt(random.nextInt(alphabet.length()))); |
| 126 | + } |
| 127 | + return stringBuilder.toString(); |
27 | 128 | }
|
28 | 129 |
|
29 | 130 | // Decodes a shortened URL to its original URL.
|
30 | 131 | public String decode(String shortUrl) {
|
31 |
| - return String.valueOf(reverseMap.get(Long.valueOf(shortUrl))); |
| 132 | + return map.get(shortUrl.substring(PREFIX.length())); |
32 | 133 | }
|
33 | 134 | }
|
34 | 135 | }
|
0 commit comments