题目

TinyURL是一种URL简化服务, 比如:当你输入一个URL https://leetcode.com/problems/design-tinyurl 时,它将返回一个简化的URL http://tinyurl.com/4e9iAk.

要求:设计一个 TinyURL 的加密 encode 和解密 decode 的方法。你的加密和解密算法如何设计和运作是没有限制的,你只需要保证一个URL可以被加密成一个TinyURL,并且这个TinyURL可以用解密方法恢复成原本的URL。

方案一(Huffman编码)

  1. // 为了方便不在进行 int -> hex
  2. type CodecTable struct {
  3. t map[string]string
  4. revT map[string]string
  5. }
  6. func (c CodecTable) Encode(str string) string {
  7. var b bytes.Buffer
  8. for i := range str {
  9. b.WriteString(c.t[string(str[i])])
  10. }
  11. return b.String()
  12. }
  13. func (c CodecTable) Decode(str string) string {
  14. var b bytes.Buffer
  15. word := ""
  16. for i := range str {
  17. word += string(str[i])
  18. if _, ok := c.revT[word]; ok {
  19. b.WriteString(c.revT[word])
  20. word = ""
  21. }
  22. }
  23. return b.String()
  24. }
  25. // Huffman Tree 的一个节点
  26. type HuffNode struct {
  27. // 使用 string 是为了方便 debug
  28. value string
  29. priority int
  30. // The index is needed by update and is maintained by the heap.Interface methods.
  31. index int // The index of the item in the heap.
  32. left *HuffNode
  33. right *HuffNode
  34. }
  35. func (h *HuffNode) GetCodeCTable() *CodecTable {
  36. t := map[string]string{}
  37. preOrder(h, []string{}, t)
  38. revT := map[string]string{}
  39. for k, v := range t {
  40. revT[v] = k
  41. }
  42. return &CodecTable{
  43. t: t,
  44. revT: revT,
  45. }
  46. }
  47. func preOrder(h *HuffNode, path []string, t map[string]string) {
  48. if h == nil {
  49. return
  50. }
  51. path = append(path, "0")
  52. preOrder(h.left, path, t)
  53. path = path[:len(path)-1]
  54. path = append(path, "1")
  55. preOrder(h.right, path, t)
  56. path = path[:len(path)-1]
  57. // 叶子节点
  58. if h.left == nil && h.right == nil {
  59. t[h.value] = strings.Join(path, "")
  60. }
  61. }
  62. type PriorityQueue []*HuffNode
  63. func (pq PriorityQueue) Len() int { return len(pq) }
  64. func (pq PriorityQueue) Less(i, j int) bool {
  65. return pq[i].priority < pq[j].priority
  66. }
  67. func (pq PriorityQueue) Swap(i, j int) {
  68. pq[i], pq[j] = pq[j], pq[i]
  69. pq[i].index = i
  70. pq[j].index = j
  71. }
  72. func (pq *PriorityQueue) Push(x interface{}) {
  73. n := len(*pq)
  74. item := x.(*HuffNode)
  75. item.index = n
  76. *pq = append(*pq, item)
  77. }
  78. func (pq *PriorityQueue) Pop() interface{} {
  79. old := *pq
  80. n := len(old)
  81. item := old[n-1]
  82. old[n-1] = nil // avoid memory leak
  83. item.index = -1 // for safety
  84. *pq = old[0 : n-1]
  85. return item
  86. }
  87. func BuildHuffmanTree(m map[string]int) *HuffNode {
  88. pq := make(PriorityQueue, len(m))
  89. i := 0
  90. for value, priority := range m {
  91. pq[i] = &HuffNode{
  92. value: value,
  93. priority: priority,
  94. index: i,
  95. }
  96. i++
  97. }
  98. heap.Init(&pq)
  99. for pq.Len() > 1 {
  100. left := heap.Pop(&pq).(*HuffNode)
  101. right := heap.Pop(&pq).(*HuffNode)
  102. newNode := &HuffNode{
  103. left: left,
  104. right: right,
  105. priority: left.priority + right.priority,
  106. }
  107. heap.Push(&pq, newNode)
  108. }
  109. root := heap.Pop(&pq).(*HuffNode)
  110. return root
  111. }
  112. type Codec struct {
  113. t *CodecTable
  114. }
  115. func Constructor() Codec {
  116. return Codec{}
  117. }
  118. // Encodes a URL to a shortened URL.
  119. // https://leetcode.com/problems/design-tinyurl
  120. func (this *Codec) encode(longUrl string) string {
  121. counter := map[string]int{}
  122. for i := range longUrl {
  123. counter[string(longUrl[i])]++
  124. }
  125. tree := BuildHuffmanTree(counter)
  126. this.t = tree.GetCodeCTable()
  127. return this.t.Encode(longUrl)
  128. }
  129. // Decodes a shortened URL to its original URL.
  130. func (this *Codec) decode(shortUrl string) string {
  131. return this.t.Decode(shortUrl)
  132. }
  133. /**
  134. * Your Codec object will be instantiated and called as such:
  135. * obj := Constructor();
  136. * url := obj.encode(longUrl);
  137. * ans := obj.decode(url);
  138. */
  1. 使用 最小堆(优先级队列)构建 Huffman 树;
  2. 前序遍历 Huffman 树,构建转换表;
  3. 利用转换表进行编解码。

    原文

    https://leetcode-cn.com/problems/encode-and-decode-tinyurl/