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..i−1]),check(s[j..i−1]) 表示子串 s[j..i-1]s[j..i−1] 是否出现在字典中。
2.回溯法:这种方法效率较低,很难通过,但加上import functools
实现
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.
题目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.
题目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.
题目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。