当前位置 博文首页 > DL_fan的博客:leetcode hot100(第二部分) + python(c++)
50-1. 乘积最大子数组
思路1:找到状态转移方程:
maxf[i]:表示在i处最大连乘数
minf[i]:表示在i处最小连乘数
maxf[i] = max(nums[i],nums[i]*minf[i-1],nums[i]*maxf[i-1])
minf[i] = min(nums[i],nums[i]*minf[i-1],nums[i]*maxf[i-1])
#maxf[i]:表示在i处最大连乘数
#minf[i]:表示在i处最小连乘数
#maxf[i] = max(nums[i],nums[i]*minf[i-1],nums[i]*maxf[i-1])
#minf[i] = min(nums[i],nums[i]*minf[i-1],nums[i]*maxf[i-1])
class Solution:
def maxProduct(self, nums):
n = len(nums)
maxf,minf = [0]*n,[0] * n
maxf[0],minf[0] = nums[0],nums[0]
for i in range(1,n):
maxf[i] = max(nums[i], nums[i] * minf[i - 1], nums[i] * maxf[i-1])
minf[i] = min(nums[i], nums[i] * minf[i - 1], nums[i] * maxf[i-1])
print('==maxf:', maxf)
return max(maxf)
nums = [2,3,-2,4]
sol = Solution()
sol.maxProduct(nums)
思路2:优化版 由于第 i?个状态只和第 i - 1个状态相关,可以只用两个变量来维护 i - 1时刻的状态,一个维护 max, 一个维护 min
class Solution:
def maxProduct(self, nums):
min_value = nums[0]
max_value = nums[0]
res = nums[0]
for i in range(1, len(nums)):
mx = max_value
mn = min_value
max_value = max(nums[i], nums[i]*mx, nums[i]*mn)
min_value = min(nums[i], nums[i]*mx, nums[i]*mn)
print('==max_value:', max_value)
print('==min_value:', min_value)
res = max(max_value, res)
print('==res:', res)
nums = [2,3,-2,4]
sol = Solution()
sol.maxProduct(nums)
50-2.三个数的最大乘积
思路:从小到大排序,如果都是正数则结果是最后三个相乘,如有正有负,结果有可能就是前两个相乘在乘以最后一个正数
class Solution:
def maximumProduct(self, nums):
nums = sorted(nums)
return max(nums[-1]*nums[-2]*nums[-3], nums[0]*nums[1]*nums[-1])
# nums = [1, 2, 3, 4]
nums = [-1, -2, 1, 2, 3]
sol = Solution()
sol.maximumProduct(nums)
51. 最小栈
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
def push(self, x: int) -> None:
self.stack.append(x)
def pop(self) -> None:
self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
return min(self.stack)
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()
c++实现:
class MinStack {
public:
stack<int> stack_A;
stack<int> min_stack;
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
stack_A.push(x);
if(min_stack.empty() || min_stack.top()>=x){
min_stack.push(x);
}
}
void pop() {
if(stack_A.top() == min_stack.top()){
min_stack.pop();
}
stack_A.pop();
}
int top() {
return stack_A.top();
}
int min() {
return min_stack.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(x);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->min();
*/
52.多数元素
排序:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
return sorted(nums)[len(nums)//2]
投票法(最优解):
class Solution:
def majorityElement(self, nums: List[int]) -> int:
votes = 0
for num in nums:
if votes == 0:
x = num
if num == x:
votes += 1
else:
votes -= 1
# print('==x:', x)
# print('==votes:', votes)
return x
53-1.打家劫舍
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums)==0:
return 0
if len(nums)<2:
return max(nums)
opt = [0]*len(nums)
opt[0] = nums[0]
opt[1] = max(nums[0],nums[1])
for i in range(2, len(nums)):
opt[i] = max(opt[i-2]+nums[i],opt[i-1])
print('=opt:', opt)
return max(opt)
nums = [2,7,9,3,1]
sol = Solution()
sol.rob(nums)
53-2. 打家劫舍 II
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums)==0:
return 0
if len(nums)<=2:
return max(nums)
opt1 = [0] * len(nums)
opt2 = [0] * len(nums)
#不抢第一家
opt1[0] = 0
opt1[1] = nums[1]
#不抢最后一家
opt2[0] = nums[0]
opt2[1] = max(nums[:2])
for i in range(2,len(nums)):
opt1[i]=max(opt1[i-2]+nums[i], opt1[i-1])
print(opt1)
for i in range(2, len(nums)-1):
opt2[i] = max(opt2[i - 2] + nums[i], opt2[i - 1])
print(opt2)
return max(opt1[-1],opt2[-2])
nums=[1,2,3,1]
sol = Solution()
res = sol.rob(nums)
print('res:')
print(res)
53-3. 打家劫舍 III
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def helper(self,node):
if node is None:
return 0, 0
choose_l_value,no_choose_l_value = self.helper(node.left)
choose_r_value,no_choose_r_value = self.helper(node.right)
return node.val+no_choose_l_value+no_choose_r_value, max(choose_l_value,no_choose_l_value)+max(choose_r_value,no_choose_r_value)
def rob(self, root: TreeNode) -> int:
return max(self.helper(root))
54.岛屿数量
思路:递归 也就是求1的连通域个数,从1开始进行遍历,将遍历过得1依次置位0,遍历的次数就是连通域个数
# 求1的连通域个数,从1开始进行遍历,将遍历过得1依次置位0,遍历的次数就是连通域个数
class Solution:
def helper(self, i, j, h, w):
if i < 0 or i >= h or j < 0 or j >= w or self.grid[i][j] == "0":
return
self.grid[i][j] = "0"
self.helper(i - 1, j, h, w)
self.helper(i + 1, j, h, w)
self.helper(i, j-1, h, w)
self.helper(i, j+1, h, w)
def numIslands(self, grid):
if len(grid) == 0:
return []
self.grid = grid
h, w = len(grid), len(grid[0])
nums = 0
for i in range(h):
for j in range(w):
if self.grid[i][j] == "1":
nums += 1
self.helper(i, j, h, w)
print('==self.grid:', self.grid)
print('==nums:', nums)
return nums
grid = [
["1", "1", "1", "1", "0"],
["1", "1", "0", "1", "0"],
["1", "1", "0", "0", "0"],
["0", "0", "0", "0", "0"]
]
sol = Solution()
sol.numIslands(grid)
?55.反转链表
思路1:双指针?
?
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 申请两个节点,pre和 cur,pre指向None
pre = None
cur = head
# 遍历链表,while循环里面的内容其实可以写成一行
while cur:
# 记录当前节点的下一个节点
tmp = cur.next
# 然后将当前节点指向pre
cur.next = pre
# pre和cur节点都前进一位
pre = cur
cur = tmp
return pre
c++实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* temp = head;
while(head){
temp = head->next;
head->next = pre;
pre = head;
head = temp;
}
return pre;
}
};
思路2.递归法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
# pre = None
# cur = head
# while cur:
# node = cur.next
# cur.next = pre
# pre = cur
# cur = node
# return pre
if head is None or head.next is None:
return head
new_node = self.reverseList(head.next)
print('head.val',head.val)
head.next.next = head
head.next = None
return new_node
56-1.?课程表
思路:对于这种从图找拓扑排序?,只有有向无环图能够找到,将入度为0的节点先进入队列,在利用bfs进行出队处理,此时将出队的节点的下一个节点的度进行减一计数,同时遍历的节点数进行加一,最终节点都进行了遍历,则说明找到了拓扑排序.
思路1:用邻接列表
class Solution:
def canFinish(self, numCourses, prerequisites):
indegrees = [0] * numCourses # 入度列表
print('==indegrees:', indegrees)
adjacency = [[] for i in range(numCourses)] # 邻接列表 存储节点的下一个节点
print('=adjacency:', adjacency)
#得到入度和每个课程的邻接列表
for cur, pre in prerequisites:
indegrees[cur] += 1
adjacency[pre].append(cur)
print('====indegrees:', indegrees)
print('====adjacency:', adjacency)
quene = []
# 如果度为0 就进入队列
for i in range(len(indegrees)):
if indegrees[i] == 0:
quene.append(i)
print('==quene:', quene)
num_nodes = 0
while quene:
node = quene.pop(0)
num_nodes += 1
for next_node in adjacency[node]:
indegrees[next_node] -= 1 # 找出下一个点相应的度-1
if indegrees[next_node] == 0: # 入度为0
quene.append(next_node)
print('==num_nodes:', num_nodes)
return num_nodes == numCourses
# numCourses, prerequisites = 2, [[1, 0]]
# numCourses, prerequisites = 2, [[1, 0], [0, 1]]
numCourses, prerequisites = 6, [[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
sol = Solution()
res = sol.canFinish(numCourses, prerequisites)
print('res:', res)
思路2:用邻接矩阵的bfs
class Solution:
def canFinish(self, numCourses, prerequisites):
indegrees = [0] * numCourses # 度列表
adjacency = [[0 for i in range(numCourses)] for i in range(numCourses)] # 邻接矩阵 表示节点之间关系
print('==init adjacency:', adjacency)
for cur, pre in prerequisites:
indegrees[cur] += 1
adjacency[pre][cur] = 1
print('==init adjacency complete:', adjacency)
print('==init indegrees complete:', indegrees)
quene = []
for i in range(len(indegrees)):
if indegrees[i] == 0:
quene.append(i)
print('==quene:', quene)
num_nodes = 0
while quene:
node = quene.pop()
num_nodes += 1
for j in range(numCourses):
if adjacency[node][j] == 1:
next_node = j
adjacency[node][j] -= 1
indegrees[next_node] -= 1
if indegrees[next_node] == 0:
quene.append(next_node)
print('==num_nodes:', num_nodes)
return num_nodes == numCourses
# numCourses = 2
# prerequisites = [[0, 1]]
numCourses = 4
prerequisites = [[1, 0], [2, 0], [3,1],[3,2]]
sol = Solution()
sol.canFinish(numCourses, prerequisites)
56-2:课程表 II
思路:有向无环图,BFS遍历?
class Solution:
def canFinish(self, numCourses, prerequisites):
indegrees = [0] * numCourses # 入度列表
print('==indegrees:', indegrees)
adjacency = [[] for i in range(numCourses)] # 邻接列表
print('=adjacency:', adjacency)
#得到入度和每个课程的邻接列表
for cur, pre in prerequisites:
indegrees[cur] += 1
adjacency[pre].append(cur)
print('====indegrees:', indegrees)
print('====adjacency:', adjacency)
quene = []
# 如果度为0 就进入队列
for i in range(len(indegrees)):
if indegrees[i] == 0:
quene.append(i)
print('==quene:', quene)
num_nodes = 0
learn_node = []
while quene:
node = quene.pop(0)
print('=======node', node)
learn_node.append(node)
num_nodes += 1
for next_node in adjacency[node]:
indegrees[next_node] -= 1 # 找出下一个点相应的度-1
if indegrees[next_node] == 0: # 入度为0
quene.append(next_node)
print('==num_nodes:', num_nodes)
return learn_node if num_nodes == numCourses else []
# numCourses, prerequisites = 2, [[1, 0]]
# numCourses, prerequisites = 2, [[1, 0], [0, 1]]
numCourses, prerequisites = 6, [[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
sol = Solution()
res = sol.canFinish(numCourses, prerequisites)
print('res:', res)
思路2:用邻接矩阵的bfs
class Solution:
def canFinish(self, numCourses, prerequisites):
indegrees = [0] * numCourses # 度列表
adjacency = [[0 for i in range(numCourses)] for i in range(numCourses)] # 邻接矩阵 表示节点之间关系
print('==init adjacency:', adjacency)
for cur, pre in prerequisites:
indegrees[cur] += 1
adjacency[pre][cur] = 1
print('==init adjacency complete:', adjacency)
print('==init indegrees complete:', indegrees)
quene = []
for i in range(len(indegrees)):
if indegrees[i] == 0:
quene.append(i)
print('==quene:', quene)
num_nodes = 0
learn_nodes = []
while quene:
node = quene.pop()
learn_nodes.append(node)
num_nodes += 1
for j in range(numCourses):
if adjacency[node][j] == 1:
next_node = j
adjacency[node][j] -= 1
indegrees[next_node] -= 1
if indegrees[next_node] == 0:
quene.append(next_node)
print('==num_nodes:', num_nodes)
print('=learn_nodes:', learn_nodes)
return learn_nodes if num_nodes == numCourses else []
# numCourses = 2
# prerequisites = [[0, 1]]
numCourses = 4
prerequisites = [[1, 0], [2, 0], [3,1],[3,2]]
sol = Solution()
sol.canFinish(numCourses, prerequisites)
57.实现 Trie (前缀树)
思路:利用字典存储每个单词,同时用特殊字符结尾。
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = {}
self.word_end = -1
def insert(self, word):
"""
Inserts a word into the trie.
"""
curNode = self.root
for c in word:
if c not in curNode:
curNode[c] = {}
curNode = curNode[c]
curNode[self.word_end] = True
# print('==curNode:', curNode)
def search(self, word):
"""
Retu
rns if the word is in the trie.
"""
curNode = self.root
for c in word:
if c not in curNode:
return False
curNode = curNode[c]
if self.word_end not in curNode:
return False
return True
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
curNode = self.root
for c in prefix:
if c not in curNode:
return False
curNode = curNode[c]
return True
word = 'apple'
prefix = 'ad'
obj = Trie()
obj.insert(word='apple')
obj.insert(word='add')
# obj.insert(word='app')
print('tree:', obj.root)
param_2 = obj.search(word)
print('search res:', param_2)
param_3 = obj.startsWith(prefix)
print('==param_3:', param_3)
58.数组中的第K个最大元素
思路:排序 取第k个值就可
class Solution:
def quicksort(self, arr):
if len(arr) <= 1:
return arr
privot = arr[len(arr) // 2]
left = [i for i in arr if i < privot]
middle = [i for i in arr if i == privot]
right = [i for i in arr if i > privot]
# left = [arr[i] for i in range(len(arr)) if arr[i] < privot]
# middle = [arr[i] for i in range(len(arr)) if arr[i] == privot]
# right = [arr[i] for i in range(len(arr)) if arr[i] > privot]
return self.quicksort(left) + middle + self.quicksort(right)
def findKthLargest(self, nums, k):
return self.quicksort(nums)[::-1][k-1]
# nums = [3, 2, 1, 5, 6, 4]
# k = 2
nums = [3,2,3,1,2,4,5,5,6]
k = 4
sol = Solution()
res = sol.findKthLargest(nums, k)
print('res:', res)
思路2:topk问题用最小堆?
class Solution:
def findKthLargest(self, nums, k):
arr = []
heapq.heapify(arr)
for i in range(k):
heapq.heappush(arr, nums[i])
for i in range(k, len(nums)):
heapq.heappush(arr, nums[i])
heapq.heappop(arr)
print('==arr:', arr)
return arr[0]
arr = [3,2,1,5,6,4]
k = 2
sol = Solution()
sol.findKthLargest(arr, k)
59.最大正方形
思路:题目既然求最大正方形面积,那就先由2*2正方形拓展更大即可,也就是可以用动态规划来存储左上角,左边,上边的最小值,也是正方形边长
1.转移方程为 dp[i][j] = min(dp[i-1][j],dp[i][j-1].dp[i-1][j-1])+1
2.初始化边界条件为: dp[:][0] = matrix[:][0] dp[0][:] = matrix[0][:]
class Solution:
def maximalSquare(self, matrix):
max_side = 0
h,w = len(matrix),len(matrix[0])
dp = [[0 for i in range(w)] for i in range(h)]
print('初始化dp',np.array(dp))
for i in range(h):
dp[i][0] = int(matrix[i][0])
max_side = max(max_side, dp[i][0])
for i in range(w):
dp[0][i] = int(matrix[0][i])
max_side = max(max_side, dp[0][i])
print('初始化边界dp',np.array(dp))
for i in range(1,h):
for j in range(1,w):
if matrix[i][j]=='1':
dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])+1
max_side = max(max_side, dp[i][j])
print('转移好dp',np.array(dp))
return max_side**2
matrix = [["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]]
# matrix = [["0","1"],["1","0"]]
sol = Solution()
res= sol.maximalSquare(matrix)
print(res)
60.翻转二叉树
思路:递归遍历左右子树进行交换即可
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if root is None:
return None
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.left = right
root.right = left
return root
c++实现:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root == nullptr){
return nullptr;
}
TreeNode* left = invertTree(root->left);
TreeNode* right = invertTree(root->right);
root->left = right;
root->right = left;
return root;
}
};
61.请判断一个链表是否为回文链表
利用列表将列表值进行拷贝,在判断是否是回文字符串
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
stack= []
while head:
stack.append(head.val)
head = head.next
return stack==stack[::-1]
c++实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> res;
while(head){
res.push_back(head->val);
head = head->next;
}
int left=0;
int right=res.size()-1;
while(left<right){
if(res[left]==res[right]){
left+=1;
right-=1;
}
else{
return false;
}
}
return true;
}
};
62:二叉树的最近公共祖先
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root is None or root==p or root==q:#递归终止条件 节点为空 或者节点等于p,q其中之一
return root
left = self.lowestCommonAncestor(root.left, p, q)#遍历左子树
right = self.lowestCommonAncestor(root.right, p, q)#遍历右子树
if left is None:#左子树为空 就去右子树
return right
if right is None:#右子树为空 就去左子树
return left
return root#左右子树都不为空 说明找到了节点
c++实现:
代码段 小部件
63.除自身以外数组的乘积
思路1:超时
#超时时间复杂度O(N)
class Solution:
def productExceptSelf(self, nums):
output = len(nums)*[0]
for i in range(len(nums)):
temp = 1
for j in nums[:i]:
temp*=j
for j in nums[i+1:]:
temp*=j
output[i] = temp
# print('==output:', output)
return output
nums = [1, 2, 3, 4]
sol = Solution()
sol.productExceptSelf(nums)
思路2:利用空间换时间
1.借用左右数组来存储值,L[i]代表i左边的乘积值,R[i]代表i右边的乘积值
2.最终i处的值为L[i]*R[i]
class Solution:
def productExceptSelf(self, nums):
length = len(nums)
L,R,output = [0]*length,[0]*length,[0]*length
L[0] = 1
for i in range(1, length):
L[i] = L[i-1]*nums[i-1]
print('==L:', L)
R[length-1] = 1
for i in range(length-2, -1, -1):
print('==i:', i)
R[i] = R[i + 1] * nums[i + 1]
print('==R:', R)
for i in range(length):
output[i] = L[i]*R[i]
return output
nums = [1, 2, 3, 4]
sol = Solution()
sol.productExceptSelf(nums)
64.滑动窗口最大值
思路1.超时O(n*k)
class Solution:
def maxSlidingWindow(self, nums, k):
#时间复杂度O(Nk)超时了
res = []
for i in range(len(nums)-k+1):
res.append(max(nums[i:i+k]))
return res
思路2:
动态规划:时间复杂度O(N)
1.将数组分成k+1个,剩下的一个可能不足;?
2.left数组存储每个拆分的从左到右的值,对于left来说每个块最右边元素最大;
3.right数组存储每个拆分的从右到左的值,对于right来说每个块最左边元素最大;
4.最后在利用left和right求最大值,max(left[i],right(j)) i每个块最右边元素索引,j每个块最左边元素索引