📣 独立日限时特惠: VIP通行证立减$68
查看: 2388| 回复: 8
跳转到指定楼层
上一主题 下一主题
收起左侧

[学Python/Perl] 请问在leetcode上如何重载某个类的比较函数?

全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x

比如merge k sorted lists这道题,用priority queue(heap)的解法, 因为比较的是两个listnode类的val, 需要重载listnode的__lt__函数, 我看leetcode上别人是重新定义一个更大的类(比如下面的这个priorityqueuenode), 然后用listnode初始化这个类, 想问下有没有方法可以在leetcode的格式下直接重载listnode的__lt__, 这样避免了重新定义一个新类。。。谢谢!

https://leetcode.com/problems/merge-k-sorted-lists/

别人的重载方法:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class priorityQueueNode:  #define a new class
    def __init__(self,key,val):
        self.key = key
        self.val = val
    def __lt__(self,other):  #reload the new class __lt__
        return self.key < other.key

class Solution:
    # merge every two lists

    # priority queue
# time Onlog(len(lists))
# space Olen(lists) + n
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:

        dummy = ListNode(0)
        node = dummy
        n = len(lists)
        minHeap = []
        for l in lists:
            if l:
                heapq.heappush(minHeap,priorityQueueNode(l.val,l))
        #print(minHeap)
        while minHeap:
            top = heapq.heappop(minHeap).val
            node.next = top
            node = node.next
            if top.next:
                heapq.heappush(minHeap,priorityQueueNode(top.next.val,top.next))
        return dummy.next

上一篇:AWS 考试 Webcam 要求
下一篇:Leetcode刷题笔记 #80. Remove Duplicates from Sorted Array
🔗
hjy 2020-8-14 06:40:38 | 只看该作者
全局:
本帖最后由 hjy 于 2020-8-14 06:48 编辑

这应该是重写不是重载。应该可以创建一个子类继承之后重写吧。 你创建一个子类,继承listnode, 然后再重写这个子类的__lt__. 构造函数直接继承。。或者是用lambda? 但是我忘记heappop和heappush能不能用lambda了。。

ps: 重写关系从oop的角度来讲, 父类的方法只能被子类重写。。。不创建子类重写父类的方法在oop语言里面,应该是不存在的(correct me if im wrong), 因为这本身违背了oop的原则

  1. class priorityQueueNode(ListNode):  #define a new class
  2.     def __lt__(self,other):  #reload the new class __lt__
  3.         return self.key < other.key
复制代码



评分

参与人数 1大米 +2 收起 理由
fasionfans + 2 给你点个赞!

查看全部评分

回复

使用道具 举报

🔗
Mr.p 2020-8-14 10:52:57 | 只看该作者
全局:
在两周以前我都是自己重写一个类做wrap,但是最近被朋友提醒用tuple一包就行了不需要写别的类,你只需要heappush(h,(node.val,node)) 这样就会按val排序了,而且我一般还会加一个记数i进tuple,因为tuple是按顺序来比较的,为了防止node的lt gt没有实现(我不知道有没有),放一个计数变成(node.val,i,node)这样就算val相同,比较到i肯定也会不同,就不会比较node了

评分

参与人数 1大米 +2 收起 理由
fasionfans + 2 很有用的信息!

查看全部评分

回复

使用道具 举报

🔗
magicsets 2020-8-15 15:07:14 | 只看该作者
全局:
本帖最后由 magicsets 于 2020-8-15 15:18 编辑

这里写两种方法,都是LeetCode上可以提交通过的

第一种方法就是你想要的“重写”(overwrite)ListNode 原有的 __lt__,就在class Solution前面加一行代码就可以:


  1. # 将ListNode的__lt__函数替换为自定义的一个lambda function
  2. ListNode.__lt__ = lambda self, other: self.val < other.val

  3. class Solution:
  4.     # merge every two lists

  5.     # priority queue
  6.     # time Onlog(len(lists))
  7.     # space Olen(lists) + n
  8.     def mergeKLists(self, lists: List[ListNode]) -> ListNode:
  9.         dummy = ListNode(0)
  10.         node = dummy
  11.         n = len(lists)
  12.         minHeap = []
  13.         for l in lists:
  14.             if l:
  15.                 heapq.heappush(minHeap, l)
  16.         while minHeap:
  17.             top = heapq.heappop(minHeap)
  18.             node.next = top
  19.             node = node.next
  20.             if top.next:
  21.                 heapq.heappush(minHeap, top.next)
  22.         return dummy.next
复制代码


这个方法体现了Python的动态语言特性,也就是一个class的可执行代码本身也是一个object,是在运行时可以修改的数据(first-class citizen)。这是很灵活但也是危险的特性(class的行为可以在其定义区域之外做任意改动),实际工程项目里面应该是会禁止或者非常小心做这样的事情的。


第二种是自定义一个通用的PriorityQueue,使用lambda function注入compare函数。稍微要多写一点代码,但都是封装在PriorityQueue内部所以代码结构反而会更清晰。这个如果在面试的时候写出来应该是比较加分的,因为展示了抽象能力:

  1. class PriorityQueueBucket:
  2.     def __init__(self, key, value):
  3.         self.key = key
  4.         self.value = value
  5.    
  6.     def __lt__(self, other):
  7.         return self.key < other.key

  8. # 支持自定义comparator的PriorityQueue
  9. class PriorityQueue:
  10.     import heapq
  11.     import functools
  12.    
  13.     def __init__(self, cmp = lambda x, y: x > y):
  14.         self.container = []
  15.         self.getKey = functools.cmp_to_key(
  16.             lambda x, y: -1 if cmp(x, y) else 1 if cmp(y, x) else 0)

  17.     def __len__(self):
  18.         return len(self.container)

  19.     def push(self, item):
  20.         heapq.heappush(self.container, PriorityQueueBucket(self.getKey(item), item))

  21.     def pop(self):
  22.         return heapq.heappop(self.container).value


  23. class Solution:
  24.     # merge every two lists

  25.     # priority queue
  26.     # time Onlog(len(lists))
  27.     # space Olen(lists) + n
  28.     def mergeKLists(self, lists: List[ListNode]) -> ListNode:
  29.         dummy = ListNode(0)
  30.         node = dummy
  31.         n = len(lists)
  32.         minHeap = PriorityQueue(lambda x, y: x.val < y.val)
  33.         for l in lists:
  34.             if l:
  35.                 minHeap.push(l)
  36.         while minHeap:
  37.             top = minHeap.pop()
  38.             node.next = top
  39.             node = node.next
  40.             if top.next:
  41.                 minHeap.push(top.next)
  42.         return dummy.next
复制代码

评分

参与人数 1大米 +2 收起 理由
fasionfans + 2 给你点个赞!

查看全部评分

回复

使用道具 举报

🔗
 楼主| fasionfans 2020-8-30 00:25:55 | 只看该作者
全局:
hjy 发表于 2020-8-14 06:40
这应该是重写不是重载。应该可以创建一个子类继承之后重写吧。 你创建一个子类,继承listnode, 然后再重写 ...

谢谢, 终于能区分重写和重载了。 :)
回复

使用道具 举报

🔗
 楼主| fasionfans 2020-8-30 00:38:07 | 只看该作者
全局:
Mr.p 发表于 2020-8-14 10:52
在两周以前我都是自己重写一个类做wrap,但是最近被朋友提醒用tuple一包就行了不需要写别的类,你只需要hea ...

这个方法很简洁, one more question, 如果需要比较两个不同类型的值, 比如top k frequent words 这道题, 需要先按照每个词出现的频率排序, 如果两个词出现频率一样就按那个哪个词有“lower alphabetical order”排序。还能用这个tuple 方法吗? 我试了一下以下的代码, 似乎对有的测试例比如input=["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"] 排序就不对了,不知道大神们有啥idea?谢谢!
ttps://leetcode.com/problems/top-k-frequent-words/,
class Solution:
    def topKFrequent(self, words: List[str], k: int) -> List[str]:
        d=collections.Counter(words)
        h=[]
        res=[]
        for key, val in d.items():
            heappush(h, (val, key))
            if len(h)>k:
                heappop(h)
        
        while h:
            tmp=h.pop()
            res.append(tmp[1])
        return reversed(res)
        
回复

使用道具 举报

🔗
 楼主| fasionfans 2020-8-30 00:38:40 | 只看该作者
全局:
magicsets 发表于 2020-8-15 15:07
这里写两种方法,都是LeetCode上可以提交通过的

第一种方法就是你想要的“重写”(overwrite)ListNode  ...

谢谢, 第2种方法太牛了!
回复

使用道具 举报

🔗
Mr.p 2020-8-30 03:28:58 | 只看该作者
全局:
fasionfans 发表于 2020-8-30 00:38
这个方法很简洁, one more question, 如果需要比较两个不同类型的值, 比如top k frequent words 这道题 ...

如果我没理解错哈,你要先按频率排序,再按字母序那就压入一个这样的tuple (频数,原字符串,其他信息) heap在比较大小的时候会按tuple内的各个元素的先后顺序拿来作比较,若第一个元素相同,则比较第二个。
这样你把频数和字符串本身都放进去应该就可以了,这也是为什么我前面的例子里要加一个计数i进tuple,为了防止val相同的时候去比较node,然而node的lt和gt又没有正确的实现这样的情况。

回复

使用道具 举报

🔗
 楼主| fasionfans 2020-8-30 06:10:35 | 只看该作者
全局:
嗯嗯, 你的理解是对的, 我就是这么压入tuple的, 那个key就是原字符串, 然而过不了测视例。 :D
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表