• leetcode刷题-131~


    题目131

    分割回文串

    给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

    返回 s 所有可能的分割方案。

    示例:

    输入: "aab"
    输出:
    [
    ["aa","b"],
    ["a","a","b"]
    ]

    思路

    递归的方式:若当前字符串是回文串则添加,左右指针移动到此回文串后。不管现在是否为回文串,右指针向后移动(覆盖所有可能)

    实现

    class Solution:
        def partition(self, s: str) -> List[List[str]]:
            result = []
            def par(left ,right):
                while left < right:
                    if s[left] != s[right]:
                        return False
                    left += 1
                    right -= 1
                return True
    
            def split(left,right,cur):
                if left > right or right > len(s)-1:
                    return
                if par(left,right) is True:
                    temp = s[left:right+1]
                    if right == len(s) -1:
                        result.append(cur+[temp])
                    split(right+1,right+1,cur+[temp])
                split(left,right+1,cur)            
            split(0, 0, [])
            return result

    题目133

    克隆图

    给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。

    图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。

    class Node {
    public int val;
    public List<Node> neighbors;
    }

    思路

    广度优先遍历

    实现

    class Solution:
        def cloneGraph(self, node: 'Node') -> 'Node':
            if not node:
                return 
            nodes = [Node()]*100
            unvisit = []
            unvisit.append(node)
            nodes[node.val -1] = Node(node.val)
            idx = 0
            while unvisit:
                cur = unvisit[0]
                del unvisit[0]
                for i in cur.neighbors:
                    if nodes[i.val-1].val is 0:
                        unvisit.append(i)
                        nodes[i.val-1] = Node(i.val)
                    nodes[cur.val-1].neighbors.append(nodes[i.val-1])
    
            return nodes[node.val -1]

    题目134

    加油站

    在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

    你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

    如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

    说明: 

    如果题目有解,该答案即为唯一答案。
    输入数组均为非空数组,且长度相同。
    输入数组中的元素均为非负数。
    示例 1:

    输入:
    gas = [1,2,3,4,5]
    cost = [3,4,5,1,2]

    输出: 3

    思路

    检查每个加油站能否达成目标,但O{N^2}的时间复杂度太高了.

    可以一次遍历完成,算法如下:(参考官网解答)

    初始化 total_tank 和 curr_tank 为 0 ,并且选择 0 号加油站为起点。

      遍历所有的加油站:

      每一步中,都通过加上 gas[i] 和减去 cost[i] 来更新 total_tank 和 curr_tank 。

      如果在 i + 1 号加油站, curr_tank < 0 ,将 i + 1 号加油站作为新的起点,同时重置 curr_tank = 0 ,让油箱也清空。

    如果 total_tank < 0 ,返回 -1 ,否则返回 starting station。

    实现

    class Solution:
        def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
            l = len(gas)
            total, cur = 0 ,0
            result = 0
            for i in range(l):
                cur += gas[i] - cost[i]
                total += gas[i] - cost[i]
                if cur < 0:
                    result = i + 1
                    cur = 0
            return result if total >= 0 else -1
                    

    题目136

    只出现一次的数字

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

    思路

    异或

    实现

    class Solution:
        def singleNumber(self, nums: List[int]) -> int:
            result = 0
            for i in nums:
                result ^= i
            return result

    题目137

    只出现一次的数字

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

    思路

    异或永远的神

    实现

    class Solution:
        def singleNumber(self, nums: List[int]) -> int:
            result = 0
            result3 = 0
            for i in nums:
                result = (i^result) & ~result3
                result3 = (i^result3) & ~result
            return result

    题目138

    复制带随机指针的链表

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

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

    思路

    此题和有向图的遍历类似,深度优先遍历

    实现

    """
    # Definition for a Node.
    class Node:
        def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
            self.val = int(x)
            self.next = next
            self.random = random
    """
    
    class Solution:
        def copyRandomList(self, head: 'Node') -> 'Node':
            self.visited = {}
            return self.copy(head)
    
        def copy(self, node):
            if not node:
                return 
            if node in self.visited:
                return self.visited[node]
            new = Node(node.val)
            self.visited[node] = new
            new.next = self.copy(node.next)
            new.random = self.copy(node.random)
            return new
                

    题目139

    单词拆分

    给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。

    说明:

    拆分时可以重复使用字典中的单词。
    你可以假设字典中没有重复的单词。
    示例 1:

    输入: s = "leetcode", wordDict = ["leet", "code"]
    输出: true
    解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。

    思路

    1.动态规划:与跳楼思路类似dp[i]=dp[j] && check(s[j..i1]),check(s[j..i1]) 表示子串 s[j..i-1]s[j..i1] 是否出现在字典中。

    2.回溯法:这种方法效率较低,很难通过,但加上import functools @functools.lru_cache(None)则不会超时

    实现

    1.
    class Solution:
        def wordBreak(self, s: str, wordDict: List[str]) -> bool:
            n=len(s)
            dp=[False for _ in range(n+1)]
            dp[0]=True
            for right in range(1,n+1):
                for left in range(right):
                    if(dp[left] and (s[left:right] in wordDict)):
                        dp[right] = True
                        break
            return dp[-1]
    2.
    class Solution:
        def wordBreak(self, s: str, wordDict: List[str]) -> bool:
            import functools
            @functools.lru_cache(None)
            def mov(sub):
                if not sub:
                    return True
                result = False
                for i in range(1,len(sub)+1):
                    if sub[:i] in wordDict:
                        result = result or mov(sub[i:])
                return result
            return mov(s)

    题目141

    环形链表

    给定一个链表,判断链表中是否有环。

    如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

    如果链表中存在环,则返回 true 。 否则,返回 false 。

    进阶:

    你能用 O(1)(即,常量)内存解决此问题吗?

    思路

    1.哈希列表

    2.快慢指针

    实现

    2.
    class
    Solution: def hasCycle(self, head: ListNode) -> bool: if not head or not head.next: return False; fast = head.next slow = head while fast != slow: if not fast or not fast.next: return False; fast = fast.next.next slow = slow.next return True

    题目142

    环形链表II

    给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

    说明:不允许修改给定的链表。

    思路

    1.记录遍历过的点

    2.快慢指针

    实现

    1.
    class
    Solution: def detectCycle(self, head: ListNode) -> ListNode: visitd = [] while head: if head in visitd: return head visitd.append(head) head = head.next return None

    题目143

    重排链表

    给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
    将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

    你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

    示例 1:

    给定链表 1->2->3->4, 重新排列为 1->4->2->3.

    思路

    先利用快慢指针找到中点,然后反转后半条链表,然后合并两条链表

    实现

    虽然跑痛了,但逻辑有问题
    class
    Solution: def reorderList(self, head: ListNode) -> None: """ Do not return anything, modify head in-place instead. """ if not head or not head.next: return head def reverse(node): pre = None cur = node h = node while cur: h = cur temp = cur.next cur.next = pre pre = cur cur = temp return h def mid(node): slow = node fast = node.next while fast and fast.next: if fast: slow = slow.next fast = fast.next.next return slow second = mid(head) new = reverse(second.next) one, two = head, new while two.next: temp = one.next one.next = two temp2 = two.next two.next = temp one = temp two = temp2 if one.next == second: temp = one.next temp.next = None two.next = temp one.next = two

    题目144

    二叉树的前序遍历

    给定一个二叉树,返回它的 前序 遍历。

    思路

    1.递归

    2.迭代

    实现

    1.
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def preorderTraversal(self, root: TreeNode) -> List[int]:
            result = []
            
            def pre(node):
                if not node:
                    return
                result.append(node.val)
                pre(node.left)
                pre(node.right)
            
            pre(root)
            return result
    2.
    class Solution:
        def preorderTraversal(self, root: TreeNode) -> List[int]:
            result = []
            stack = []
            if not root:
                return result
            stack.append(root)
            while stack:
                cur = stack.pop()
                result.append(cur.val)
                if cur.right:
                    stack.append(cur.right)
                if cur.left:
                    stack.append(cur.left)  
            return result

    题目145

    二叉树的后序遍历

    给定一个二叉树,返回它的 后序 遍历。

    思路

    1.递归

    2.迭代:比较复杂,需要考虑在决定是否可以输出当前节点的值的时候,需要考虑其左右子树是否都已经遍历完成。因此加入visited标志

    实现

    1.
    class Solution:
        def postorderTraversal(self, root: TreeNode) -> List[int]:
            result = []
    
            def post(node):
                if not node:
                    return
                post(node.left)
                post(node.right)
                result.append(node.val)
            post(root)
            return result
    2.
    class Solution:
        def postorderTraversal(self, root: TreeNode) -> List[int]:
            result = []
            if not root:
                return []
            stack =[]
            stack.append(root)
            visited = []
            while stack:
                cur = stack.pop()
                if (not cur.left and not cur.right) or cur in visited:
                    result.append(cur.val)
                    continue
                if (cur.left or cur.right) and cur not in visited:
                    stack.append(cur)
                if cur.right:
                    stack.append(cur.right)
                if cur.left:
                    stack.append(cur.left)
                visited.append(cur)
            return result

    题目146

    LRU缓存机制

    运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

    获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
    写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

    思路

    我用的数组,答案用的双向链表来存储最近使用

    实现

    class LRUCache:
    
        def __init__(self, capacity: int):
            self.capacity = capacity
            self.cache = {}
            self.use = []
        def get(self, key: int) -> int:
            if key in self.cache.keys():
                self.use.remove(key)
                self.use.append(key)
                return self.cache[key]
            return -1
    
        def put(self, key: int, value: int) -> None:
            dic_len = len(self.cache)
            if self.get(key) != -1:
                self.cache[key] = value
            else:
                if dic_len != self.capacity:
                    self.cache[key] = value
                    self.use.append(key)
                else:
                    index = self.use[0]
                    del self.use[0]
                    del self.cache[index]
                    self.cache[key] = value
                    self.use.append(key)
    
    
    
    
    
    # Your LRUCache object will be instantiated and called as such:
    # obj = LRUCache(capacity)
    # param_1 = obj.get(key)
    # obj.put(key,value)

    题目147

    对链表进行插入排序

    思路

    实现

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def insertionSortList(self, head: ListNode) -> ListNode:
            begin = ListNode(None)
            begin.next = head
            
            cur = begin
            while cur.next:
                tmp = cur.next.next
                res,po = self.removeNode(cur)
                self.searchNode(res,begin)
                cur = ListNode(None)
                cur.next = tmp
            return begin.next
            '''
            res,po = self.removeNode(begin)
            self.searchNode(res,begin)
            print(begin,res,po)
            '''
            
        def removeNode(self, pre):
            node = pre.next
            #pre.next = node.next
            post = node.next
            node.next = None
            pre.next = None
            return node,post
        
        def searchNode(self, node, begin):
            last = begin
            begin = begin.next
            while begin:
                if begin.val < node.val:
                    last = begin
                    begin =begin.next
                else:
                    break  
            tmp = last.next
            node.next = tmp
            last.next = node
                

    题目148

    排序链表

    在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

    思路

    1.归并排序(递归)

    2.归并排序(从底至顶)

    实现

    1.
    class Solution:
        def sortList(self, head: ListNode) -> ListNode:
            if not head or not head.next:
                return head
            slow = head
            fast = head.next
            while fast and fast.next:
                slow = slow.next
                fast = fast.next.next
            mid = slow.next
            slow.next = None
            node1 = self.sortList(head)
            node2 = self.sortList(mid)
            result = self.mergeList(node1, node2)
            return result
    
        def mergeList(self, node1, node2):
            head = ListNode()
            first = head
            while node1 and node2:
                if node1.val < node2.val:
                    first.next = node1
                    node1 = node1.next
                else:
                    first.next = node2
                    node2 = node2.next
                first = first.next
            if not node1:
                first.next = node2
            if not node2:
                first.next = node1
            return head.next

    题目150

    逆波兰表达式求值

    根据 逆波兰表示法,求表达式的值。

    有效的运算符包括 +-*/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

    思路

    实现

    class Solution:
        def evalRPN(self, tokens: List[str]) -> int:
            stack =[]
            sym = "+-*/"
            index = 0
            while index < len(tokens): 
                op = tokens[index]
                if op in "+-*/":
                    op2 = stack.pop()
                    op1 = stack.pop()
                    if op is "+":
                        op =op1 + op2
                    elif op is "-":
                        op =op1 - op2
                    elif op is "*":
                        op =op1 * op2
                    elif op is "/":
                        op = op1// op2
                        if op < 0:
                            op = op+1
                stack.append(int(op))
                index += 1
                print(stack)
            return stack[0]

    题目151

    翻转字符串里的单词

    给定一个字符串,逐个翻转字符串中的每个单词。

    思路

    实现

    class Solution:
        def reverseWords(self, s: str) -> str:
            result = ""
            temp = ""
            s = s+" "
            for i in range(len(s)):
                if s[i] != " ":
                    temp += s[i]
                elif s[i] == " " and s[i-1] != " ":
                    result = temp + " " +result
                    temp = ""
            return result[:-1]

    题目152

    乘积的最大子数组

    给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

    思路

    动态规划:当前最大子数组 = 之前的最大子数组+ 当前元素,但是由于负数和0的存在,需要考虑最小值*负数变成最大子数组,因此需要两个记录,最大正数和最大负数。

    实现

    class Solution:
        def maxProduct(self, nums: List[int]) -> int:
            l = len(nums)
            result = nums[0]
            lastpos = 1
            lastneg = 1
            for i in range(l):
                curpos = lastpos * nums[i]
                curneg = lastneg * nums[i]
                lastpos = max(curpos,curneg,nums[i])
                lastneg = min(curpos,curneg,nums[i])
                if lastpos > result:
                    result = lastpos
            return result

    题目143

    寻找旋转排序数组中的最小值

    假设按照升序排序的数组在预先未知的某个点上进行了旋转。

    ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

    请找出其中最小的元素。

    你可以假设数组中不存在重复元素。

    思路

    二分法

    实现

    class Solution:
        def findMin(self, nums: List[int]) -> int:
            left,right = 0, len(nums)-1
            while left < right:
                mid = (left + right)//2
                if nums[mid] > nums[right]:
                    left =mid + 1
                else:
                    right = mid
            return nums[left]

    题目155

    最小栈

    设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

    push(x) —— 将元素 x 推入栈中。
    pop() —— 删除栈顶的元素。
    top() —— 获取栈顶元素。
    getMin() —— 检索栈中的最小元素。

    思路

    实现

    class MinStack:
    
        def __init__(self):
            """
            initialize your data structure here.
            """
            self.result = []
            self.min = float("inf")
    
    
        def push(self, x: int) -> None:
            self.result.append(x)
            if x < self.min:
                self.min = x
    
        def pop(self) -> None:
            tmp = self.result.pop()
            leng = len(self.result)
            if tmp == self.min:
                self.min = float("inf")
                for i in range(leng):
                    self.min = min(self.min, self.result[i])
    
        def top(self) -> int:
            return self.result[-1]
    
        def getMin(self) -> int:
            return self.min
    
    
    
    # Your MinStack object will be instantiated and called as such:
    # obj = MinStack()
    # obj.push(x)
    # obj.pop()
    # param_3 = obj.top()
    # param_4 = obj.getMin()

    题目160

    相交链表

    编写一个程序,找到两个单链表相交的起始节点。

    思路

    1.哈希表

    2.相交链表

    实现

    1.
    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
            node1 = set()
            while headA != None:
                node1.add(headA)
                headA = headA.next
            while headB != None:
                if headB in node1:
                    return headB
                headB = headB.next
    2.
    class Solution:
        def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
         if not headA or not headB:
            return None
    nodeA, nodeB
    = headA, headB while nodeA != nodeB: nodeA = nodeA.next if nodeA else headB nodeB = nodeB.next if nodeB else headA return nodeA

    题目162

    寻找峰值

    峰值元素是指其值大于左右相邻值的元素。

    给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。

    数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。

    你可以假设 nums[-1] = nums[n] = -∞

    思路实现

    class Solution:
        def findPeakElement(self, nums: List[int]) -> int:      
            nums = [float("-inf")] + nums + [float("-inf")]
            leng = len(nums)
            for i in range(1,leng-1):
                if nums[i] > nums[i-1] and nums[i] > nums[i+1]:
                    return i - 1

    题目162

    比较版本号

    比较两个版本号 version1 和 version2。
    如果 version1 > version2 返回 1,如果 version1 < version2 返回 -1, 除此之外返回 0。

    思路实现

    class Solution:
        def compareVersion(self, version1: str, version2: str) -> int:
            v1 = version1.split('.')
            v2 = version2.split('.')
            l1,l2 = len(v1),len(v2)
            if l1 > l2:
                v2 = v2 + ['0']*(l1-l2)
                slen = l1
            else:
                v1 = v1 + ['0']*(l2-l1)
                slen = l2
            for i in range(slen):
                if int(v1[i]) < int(v2[i]):
                    return -1
                if int(v1[i]) > int(v2[i]):
                    return 1
            return 0
  • 相关阅读:
    跨公司销售利润中心替代
    [WCF学习笔记] 我的WCF之旅(1):创建一个简单的WCF程序
    linux操作常用命令
    java lambda表达式
    关于lock和synchronized的选择
    ssh免密登陆(简单快捷)
    su和sudo的区别
    Linux常用查找命令
    vmware完整克隆(linux)
    springboot2.0拦截器和webconfigure配置
  • 原文地址:https://www.cnblogs.com/mgdzy/p/13708785.html
Copyright © 2020-2023  润新知