哈希表相关题目-python

栈&队列&哈希表&堆-python  https://blog.csdn.net/qq_19446965/article/details/102982047

1、O(1)时间插入、删除和获取随机元素

设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构。

insert(val):当元素 val 不存在时,向集合中插入该项。
remove(val):元素 val 存在时,从集合中移除该项。
getRandom:随机返回现有集合中的一项。每个元素应该有相同的概率被返回。
示例 :

// 初始化一个空的集合。
RandomizedSet randomSet = new RandomizedSet();

// 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomSet.insert(1);

// 返回 false ,表示集合中不存在 2 。
randomSet.remove(2);

// 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomSet.insert(2);

// getRandom 应随机返回 1 或 2 。
randomSet.getRandom();

// 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
randomSet.remove(1);

// 2 已在集合中,所以返回 false 。
randomSet.insert(2);

// 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
randomSet.getRandom();

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/insert-delete-getrandom-o1

class RandomizedSet(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.nums = []
        self.maps =  {}     

    def insert(self, val):
        """
        Inserts a value to the set. Returns true if the set did not already contain the specified element.
        :type val: int
        :rtype: bool
        """
        if val in self.maps:
            return False
        
        self.nums.append(val)
        self.maps[val] = len(self.nums) - 1
        return True 

    def remove(self, val):
        """
        Removes a value from the set. Returns true if the set contained the specified element.
        :type val: int
        :rtype: bool
        """
        if val not in self.maps:
            return False

        # 将末尾的值移到待删除元素的位置
        index = self.maps.get(val)
        last_val = self.nums[-1]
        self.nums[index] = last_val
        self.maps[last_val] = index
        # 删除最后一个元素
        self.nums.pop() 
        # 删除被删除元素的index
        del self.maps[val]
        return True
        
    def getRandom(self):
        """
        Get a random element from the set.
        :rtype: int
        """
        return random.choice(self.nums)

2、O(1) 时间插入、删除和获取随机元素 - 允许重复

示例:

// 初始化一个空的集合。
RandomizedCollection collection = new RandomizedCollection();

// 向集合中插入 1 。返回 true 表示集合不包含 1 。
collection.insert(1);

// 向集合中插入另一个 1 。返回 false 表示集合包含 1 。集合现在包含 [1,1] 。
collection.insert(1);

// 向集合中插入 2 ,返回 true 。集合现在包含 [1,1,2] 。
collection.insert(2);

// getRandom 应当有 2/3 的概率返回 1 ,1/3 的概率返回 2 。
collection.getRandom();

// 从集合中删除 1 ,返回 true 。集合现在包含 [1,2] 。
collection.remove(1);

// getRandom 应有相同概率返回 1 和 2 。
collection.getRandom();

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/insert-delete-getrandom-o1-duplicates-allowed

1)把某个数在数组中出现的所有的位置用dict的形式存储下来

2)重复元素用set存下来,用于判断

3)删除一个数的时候,就是从这个 list 里随便拿走一个数(比如最后一个数)

class RandomizedCollection(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.nums = []
        self.maps = collections.defaultdict(set)

    def insert(self, val):
        """
        Inserts a value to the collection. Returns true if the collection did not already contain the specified element.
        :type val: int
        :rtype: bool
        """
        self.nums.append(val)
        self.maps[val].add(len(self.nums)-1)
        return len(self.maps[val]) == 1
        

    def remove(self, val):
        """
        Removes a value from the collection. Returns true if the collection contained the specified element.
        :type val: int
        :rtype: bool
        """
        if not self.maps[val]:
            return False
        
        index = self.maps[val].pop()
        self.nums[index] = None
        return True

    def getRandom(self):
        """
        Get a random element from the collection.
        :rtype: int
        """
        x = None
        while x is None:   # 注意:这里不能写成while not x:
            x = random.choice(self.nums)
        return x

3、 复制带随机指针的链表

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的深拷贝。 

示例:

输入:
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}

解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer

首先,先复习一下正常链表的拷贝:

class Node(object):
    def __init__(self, val, next, random):
        self.val = val
        self.next = next
        self.random = random

  

def copy_list(head):
    if not head:
        return None

    new_head = Node(head.val)
    p = head
    q = new_head
    while p:
        if p.next:
            q.next = Node(p.next.val)
        else:
            q.next = None
        p = p.next
        q = q.next
    
    return new_head

此题还要存储一下random节点

class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: Node
        :rtype: Node
        """
        if head == None:
            return None

        maps = {}
        new_head = Node(head.val, None, None)
        maps[head] = new_head
        p = head
        q = new_head
        while p:
            q.random = p.random
            if p.next:
                q.next = Node(p.next.val, None, None)
                maps[p.next] = q.next
            else:
                q.next = None  
            p = p.next
            q = q.next
            
        p = new_head
        while p:
            if p.random:
                p.random = maps.get(p.random)
            p = p.next
        
        return new_head

4、 乱序字符串

给出一个字符串数组S,找到其中所有的乱序字符串(Anagram)。如果一个字符串是乱序字符串,那么他存在一个字母集合相同,但顺序不同的字符串也在S中。

所有的字符串都只包含小写字母

样例1:

输入:["lint", "intl", "inlt", "code"]
输出:["lint", "inlt", "intl"]

样例 2:

输入:["ab", "ba", "cd", "dc", "e"]
输出: ["ab", "ba", "cd", "dc"]

什么是Anagram?

  • 如果在更改字符顺序后它们可以相同,则两个字符串是anagram。

链接:https://www.lintcode.com/problem/anagrams/description

class Solution:
    """
    @param strs: A list of strings
    @return: A list of strings
    """
    def anagrams(self, strs):
        # write your code here
        maps = collections.defaultdict(list)
        for word in strs:
            char_list = ''.join(sorted(word))
            maps[char_list].append(word)
        res = []
        for word_list in maps.values():
            if len(word_list) >= 2:
                res += word_list
        return res

5、最长连续序列

给定一个未排序的整数数组,找出最长连续序列的长度。

要求算法的时间复杂度为 O(n)。

示例:

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-consecutive-sequence

第一种:O(nlogn)

先排序,再统计

class Solution(object):
    def longestConsecutive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) <= 1:
            return len(nums)

        nums.sort()
        length = 1
        sum = 1
        for i in range(1, len(nums)):
            if nums[i] - nums[i-1] == 0:
                continue
            
            if nums[i] - nums[i-1] == 1:
                sum += 1
            else:
                if sum > length:
                    length = sum
                sum = 1
                
        if sum > length:
            length = sum
        return length

第二种:O(n)

HashSet 判断

class Solution(object):
    def longestConsecutive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        maps = set(nums)
        length = 0
    
        for num in nums:
            if num in maps:
                sum = 1
                maps.remove(num)
                l = num - 1
                r = num + 1
                while l in maps:
                    maps.remove(l)
                    l -= 1 
                    sum += 1
                while r in maps:
                    maps.remove(r)
                    r += 1
                    sum += 1
                if length < sum:
                    length = sum
                    
        return length

 

  参考:九章算法讲解 https://www.jiuzhang.com/solution/

 

 

 

posted @ 2019-11-17 22:34  知是行之始,行是知之成  阅读(256)  评论(0编辑  收藏  举报