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
posted @ 2020-09-21 21:32  maoguai  阅读(187)  评论(0编辑  收藏  举报