1. 1802. Maximum Value at a Given Index in a Bounded Array
satisfies the following conditions:
n, index, maxSum
nums.length == n
nums[i]
is a positive integer where0 <= i < n
.abs(nums[i] - nums[i+1]) <= 1
where0 <= i < n-1
.- The sum of all the elements of
nums
does not exceedmaxSum
. nums[index]
is maximized.
Return nums[index]
of the constructed array.
Idea:
1、first, initial all array to 0, buz we want to satisfies the fourth requirement
2、then, we can slowly add the nums 1 by 1, util meet the index
3、in this cycle we need to check every increase to check if meet the maxSum require
不知道关键的循环逻辑,更新index和index+-1,看答案了
注意⚠️ 1 + 2 + ... + n的等差数列和为(1+n)*n/2
此数列为 1 2 ... k-1 k(max_index) k-1... 1
2.
滑动窗口和一个数据类型priority_queues
priority stacks explain:
Python Heapq Explained - TechBeamers
use priority stack to record max and min
LeetCode - The World's Leading Online Programming Learning Platform
point:
why?
class Solution(object):
def continuousSubarrays(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
maxQ = deque()
minQ = deque()
left = 0
res = 0
for right in range(len(nums)):
while maxQ and nums[maxQ[-1]] < nums[right]:
maxQ.pop()
maxQ.append(right)
while minQ and nums[minQ[-1]] > nums[right]:
minQ.pop()
minQ.append(right)
while nums[maxQ[0]] - nums[minQ[0]] > 2:
if maxQ[0] < minQ[0]:
left = maxQ[0] + 1
maxQ.popleft()
else:
left = minQ[0] + 1
minQ.popleft()
res += right - left + 1
-
The
while
loop checks whether the difference between the maximum and minimum elements in the current subarray, i.e.,nums[maxQ[0]] - nums[minQ[0]]
, is greater than 2. If it is, it means the current subarray does not meet the specified condition. -
Inside the loop, it checks whether the index at the front of
maxQ
(maxQ[0]
) is less than the index at the front ofminQ
(minQ[0]
). This is to determine which end of the subarray has a value that contributes more to the excess difference. IfmaxQ[0] < minQ[0]
, it means that the maximum value is further to the left, and therefore, moving the left boundary (left
) to the right is a better choice. Otherwise, it means that the minimum value is further to the left. -
If
maxQ[0] < minQ[0]
, it increments theleft
boundary by one and removes the leftmost element frommaxQ
usingmaxQ.popleft()
. This operation effectively shifts the left boundary of the subarray to the right by one element. -
If
maxQ[0] >= minQ[0]
, it means the minimum value is further to the left, so it increments theleft
boundary by one and removes the leftmost element fromminQ
usingminQ.popleft()
.
3.
In two steps, the first step is to first find the individual combinations of the 2n subarrays of this array,
and the second step is to compute the minimum value of each of the subarrays and add them together
Point:
after sort then we can get the min nums:
Logic and Working of the problem:
Suppose we have a list of 6 elements say [2,1,4,5,7,9]
First task is to pair them and thus we will have 3 pairs:
1. [1,2], [4,5], [7,9] Sum of their min : 1 + 4 + 7 = 12
2. [1,2], [4,7], [5,9] Sum of thier min : 1 + 4 + 5 = 10
3. [1,2], [4,9], [5,7] Sum of their min : 1 + 4 + 5 = 10
4. [1,4], [2,5], [7,9] Sum of their min : 1 + 2 + 7 = 10
5. [1,4], [2,7], [5,9] Sum of their min : 1 + 2 + 7 = 10
6. [1,5], [2,4], [7,9] Sum of their min : 1 + 2 + 7 = 10
7. [1,4], [2,9], [5,7] Sum of their min : 1 + 2 + 5 = 8
8. [1,7], [2,4], [5,9] Sum of their min : 1 + 2 + 5 = 8
9. [1,9], [2,4], [5,7] Sum of their min : 1 + 2 + 5 = 8
10. [1,5], [2,7], [4,9] Sum of their min : 1 + 2 + 4 = 7
11. [1,7], [2,5], [4,9] Sum of their min : 1 + 2 + 4 = 7
12. [1,7], [2,9], [4,5] Sum of their min : 1 + 2 + 4 = 7
13. [1,5], [2,9], [4,7] Sum of their min : 1 + 2 + 4 = 7
14. [1,9], [2,5], [4,7] Sum of their min : 1 + 2 + 4 = 7
15. [1,9], [2,7], [4,5] Sum of their min : 1 + 2 + 4 = 7
From the above pair and their sum we can conclude that the maximum sum is obtained from the pair which are obtained after sorting. Hence the answer to the above problem will be 12 which is obtained from the pairs [1,2], [4,5], [7,9]
1)sort
2)隔一个收集
3)结果
def arrayPairSum(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums.sort()
sum_ = 0
for i in range(0,len(nums),2):
# This for loop iterates over the indices of the sorted list, starting from index 0 and incrementing by 2 in each iteration. This means it processes every second element in the sorted list.
sum_ += nums[i]
return sum_
4.
1823. Find the Winner of the Circular Game
循环删除第k个数字 use recursion or directly, it is use queue pop and push to cycle cal
Initial queue = [5, 4, 3, 2, 1]
k = 2
Pop (right) and Push k-1 friends to the back of queue(left)
[1, 5, 4, 3, 2]
Pop front element
[1, 5, 4, 3] --> 2 (looses)
Repeat
[3, 1, 5, 4]
[3, 1, 5] --> 4
[5, 3, 1]
[5, 3] --> 1
[3, 5]
[3] --> 5
Winner 3!!
class Solution(object):
def findTheWinner(self, n, k):
"""
:type n: int
:type k: int
:rtype: int
"""
queue = list(range(n, 0, -1)) #Creates list of n to 1
# 题目要求的 ,general 1- n list
cur_k = k - 1
#Pop and Push k-1 friends to the back of queue
while len(queue) != 1: #该循环一直持续到队列中只剩下一名玩家为止。
while cur_k != 0: #这个嵌套的while循环用于模拟k循环计数的过程
queue.insert(0, queue.pop()) #Popping front element and pushing it to the end of queue
#在此循环中,它获取队列中的第一个玩家(使用queue.pop())并将其重新插入队列末尾(使用 )queue.insert(0, ...)。这模拟以循环方式移动到下一个玩家。它会重复此步骤k-1多次(由 控制cur_k)。
cur_k -= 1
# 因为这里是while循环,必须一个一个删除left queue的k数字,然后知道没有k了
queue.pop() #Popping the friend that looses
cur_k = k - 1 #Resetting
return queue.pop() #Winner
5.
658. Find K Closest Elements
idea:
find the closest x and then x+1 and x-1, k--
sliding window + binary search
class Solution:
def findClosestElements(self, arr: List[int], k: int, x: int) -> List[int]:
# if the length of the array is the same as k, we can
# just return the array itself
if len(arr) == k:
return arr
# In this example, we are doing a modified binary search, instead of
# looking for a particular value, we are looking for a range of a window.
# we cannot do a regular binary search here because the sliding window
# will out of index when it slides to the last k elements at the end of
# the array. Thus, right pointer + k <= len(arr), so right = len(arr) - k
left, right = 0, len(arr) - k
# When the left and the right pointer at the same position, we've
# searched through all possible elements in arr
while left < right:
# set midpoint, in this case, the midpoint is the starting point of
# the sliding window
m = (left + right) // 2
# since midpoint is the starting point of the sliding window, thus
# the end point of the sliding window is m + k, because we are looking
# for k elements.
# use x - arr[m] to determine if the number at midpoint is greater
# than the number at m + k, which is the end point of the window,
# notice that we assume the midpoint < x here. If x - arr[m] is greater,
# which means the number on the left side starts from midpoint is further
# than the endpoint of the window, we may set left = mid + 1 to continue
# searching from the right side
if x - arr[mid] > arr[mid + k] - x:
left = mid + 1
# Otherwise, when If x - arr[m] is smaller or equal to the endpoint,
# of the window, which means the number on the
# right side starts at the window endpoint is further than the
# starting point of the window, we may set right = mid to continue
# searching to the left side
else:
right = mid
# After searching through all possible elements, return the sliding window
# itself, we use start point as left to left + k to return k elements only
return arr[left : left + k]
6.
kind like using dequeue, detect if this char already in the string, true- delete this char ( left ) and then insert in the right side, false- which means this char show first time in this string, add in right side.
这思路不行,因为要A string a
is lexicographically smaller than a string b
if in the first position where a
and b
differ, string a
has a letter that appears earlier in the alphabet than the corresponding letter in b
.
If the first min(a.length, b.length)
characters do not differ, then the shorter string is the lexicographically smaller one.
但是这个思路也是对的,只不过这个排位顺序需要注意下⚠️
Counter function:
from collections import Counter
# Create a Counter object for a string
s = "hello"
letter_counts = Counter(s)
# Access the counts for specific elements
print(letter_counts['h']) # Output: 1 (there's one 'h' in the string)
print(letter_counts['l']) # Output: 2 (there are two 'l's in the string)
# You can also use it with lists or other iterables
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
number_counts = Counter(numbers)
print(number_counts[3]) # Output: 3 (there are three 3s in the list)
solution:
class Solution:
def removeDuplicateLetters(self, s: str) -> str:
monotonic_stack = []
stack_set = set()
letters_freq = Counter(s)
for letter in s:
letters_freq[letter] -= 1
if letter not in stack_set:
while monotonic_stack and letter < monotonic_stack[-1] and letters_freq[monotonic_stack[-1]] > 0:
# 1、不为空
# 2、保持字典顺序
# 3、出现重复项
# 该行启动一个while循环,只要monotonic_stack不为空,当前字符letter按字典顺序小于堆栈顶部的字
# 并且堆栈顶部的字符仍然存在剩余的出现次数,该循环就会运行。此循环用于确保我们从堆栈中弹出字符以维持字典顺序,同时删除重复项。
removed = monotonic_stack.pop()
stack_set.remove(removed)
monotonic_stack.append(letter)
stack_set.add(letter)
return ''.join(monotonic_stack)
7.
idea:
use set() and then calculate for cycle first letter and next letter, double for cycle
暴力解法:两个cycle,没过
from collections import Counter
class Solution(object):
def findPairs(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
count = 0
num_counts = Counter(nums)
if k == 0:
for key, value in num_counts.items():
if value >= 2:
count += 1
return count
# 以上思路是对的,以下想复杂了
for num1, count1 in num_counts.items():
for num2, count2 in num_counts.items():
if abs(num1 - num2) == k:
# Check that we don't compare an element with itself
if num1 != num2:
count += 1
# Divide by 2 to avoid double-counting pairs
count //= 2
# 不用两个for 循环:
else:
for key,v in num_counts.items():
if key+k in cnum_counts:
count+=1
return count
8.
1071. Greatest Common Divisor of Strings
def gcdOfStrings(self, str1: str, str2: str) -> str:
if str1 + str2 != str2 + str1:
return ""
max_length = gcd(len(str1), len(str2))
return str1[:max_length]
# 这个剪枝挺聪明的
""" Where a and b are the two integers for which you want to find the GCD.
greatest common divisor (GCD)
import math
a = 12
b = 18
result = math.gcd(a, b)
print(f"The GCD of {a} and {b} is {result}")
6
"""
9.
idea: (me) for cycle to find the adjacent letter, and mark it, and then after the letter to find the first not adjecent letter to extract it to the last time we mark place, then continue cycle to find. two points?
# 计数小妙招:
freq = {}
for char in s:
freq[char] = freq.get(char,0)+1
class Solution(object):
def reorganizeString(self, s):
#freq_list = {}
#for char in s:
#freq_list[char] = freq_list.get(char,0)+1
freq_list = Counter(s)
max_heap = []
for char,freq in freq_list.items():
max_heap.append((-freq,char)) # negative buz this must to be
# this step means change the heap to priority heap in order
heapq.heapify(max_heap)
res = []
prev_freq, prev_char = 0, ""
while max_heap:
freq, char = heapq.heappop(max_heap)
res.append(char)
if prev_freq < 0:
heapq.heappush(max_heap, (prev_freq,prev_char))
# 用于确保频率未完全处理的字符被正确放回到max_heap. 这是重新排列字符的逻辑的关键部分
freq += 1
prev_freq, prev_char = freq, char
if len(res) != len(s):
return ""
return "".join(res)
10.
hashmap
题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。
所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
class Solution(object):
def isHappy(self, n):
"""
:type n: int
:rtype: bool
"""
result = set()
while True:
n = self.getSum(n)
if n == 1:
return True
else:
if n in result:
return False
else:
result.add(n)
def getSum(slef, n):
new_sum = 0
while n:
n, r = divmod(n,10)
# x is the dividend n.
# y is the divisor 10.
# n is quotient 商
# r is remainder 余数
new_sum += r**2
return new_sum
11.
合并二叉树
二叉树集合:
1)操作二叉树(翻转、对称、合并)
1.1 翻转二叉树
递归三部曲,
第一:确定递归函数的参数和返回值
第二:确定终止条件
第三:确定单层递归的逻辑
# 递归法:preoder
def invertTree(self, root):
if not root:
return None
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
# 层序遍历level order traversal
def invertTree(self, root):
if not root:
return None
queue = collections.deque([root])
while queue:
for i in range(len(queue)):
node = queue.popleft()
node.left, node.right = node.right, node.left
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
# check the node if have child node, if true, then add in the queue
reuturn root
1.2 对称二叉树
递归法:recursion algorithm 后序遍历:post order(因为要先取左右父树的左右子树,最后比较是否相等)
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
return self.compare(root.left, root.right)
def compare(self, left, right):
#剪枝:none node
if left is None and right is not None:
return False
elif left is not None and right is None:
return False
elif left is None and right is None:
return True
# left is not equal to right
elif left.val != right.val:
return False
outside = self.compare(left.left, right.right) # left child tree:left / right child tree: right
inside = self.compare(left.right, right.left) #左子树:右、 右子树:左
isSame = outside and inside #左子树:中、 右子树:中 (逻辑处理)
return isSame
迭代法:(Iterative method)
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
queue = collections.deque()
queue.append(root.left) # add head node of left tree in queue
queue.append(root.right) # same
while queue:
# if the tree is symmertic
leftNode = queue.popleft()
rightNode = queue.popleft()
if not leftNode and not rightNode:
# left node and right node is none
continue #?
if not leftNode or not rightNode or leftNode.val != rightNode.val # why .val
return False
queue.append(leftNode.left)
queue.append(rightNode.right)
# 1、左边最左是否跟右边最右相等?
queue.append(leftNode.right)
queue.append(rightNode.left)
# the order could change ?
# 2、左边的右是否跟右边的左相等
return True
1.3 相加二叉树
递归 - 前序
def mergeTrees(self, root1, root2):
# 递归终止条件:
# 但凡有一个节点为空, 就立刻返回另外一个. 如果另外一个也为None就直接返回None.
if not root1:
return root2
if not root2:
return root1
# 以上代码表达了root1 and root2 都非空
# 中
root1.val += root2.val
root1.left = self.mergeTrees(root1.left, root2.left)
root1.right = self.mergeTrees(root1.right, root2.right)
return root1
# ⚠️ 注意: 本题我们重复使用了题目给出的节点而不是创建新节点. 节省时间, 空间.
迭代还没看懂
12. 二叉树共同祖先
236. Lowest Common Ancestor of a Binary Tree
后序遍历,因为是从下往上的处理逻辑
【要理解后序遍历,首先要理解 二叉树的最大深度这个章节】(二叉树的高度和深度有啥区别?究竟用什么遍历顺序?很多录友搞不懂 | LeetCode:104.二叉树的最大深度_哔哩哔哩_bilibili)
递归法求最大深度:(post order)
def maxdepth(self, root):
return self.getdepth(root)
def getdepth(self, node):
if not node:
return 0
leftheight = self.getdepth(node.left)
rightheight = self.getdepth(node.right)
height = 1 + max(leftheight, rightheight)
return height
求公众祖先:
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
#return traversal(root, p, q)
# it's non neccessary to build another fucntion
#def traversal(root,p,q):
#if (root == None):
# return None
# 这里也应该返回 root buz root is None
# 这里是pq不是root left or root right
if ( root == p or root == q or root == None):
return root
# 迭代 : 后序遍历
# left
#self.left = traversal(root.left, p, q)
left = self.lowestCommonAncestor(root.left,p,q)
# right
right = self.lowestCommonAncestor(root.right,p,q)
# middle
# situation:
# 1、right/left both not none
if (left != None and right != None):
return root
elif (left != None and right == None):
return left
elif (left == None and right != None):
return right
else:
return None
13. 层序遍历
size length method(another is traversal)
class Solution(object):
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
if root is None:
return []
result=[]
queue = deque.collections([root])
size = 0
while(queue):
level = []
for _ in range(len(queue)):
cur = queue.popleft()
level.append(cur.val)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
result.append(level)
return result
14. 2Sum 3Sum 4Sum - HashMap
349. 两个数组的交集
这道题目,主要要学会使用一种哈希数据结构:unordered_set,这个数据结构可以解决很多类似的问题。
注意题目特意说明:输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序
这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。
那么用数组来做哈希表也是不错的选择,例如242. 有效的字母异位词(opens new window)
但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小。
而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
1、two sum
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
# use map and dict
# 1、first storage nums1 using map
# 2、then cycle the nums2 for search the target nums - num(in nums2)
# 3、if find -> record the index and the previous index and save it
# 4、return the result
nums1 = {}
for i,v in enumerate(nums):
# Iterate over the current element and look in the map to see if there is a match for the key
if target-v in nums1:
return[nums1[target-v], i]
nums1[v] = i
# If no matching pair is found, add the visited element and subscript to the map
return []
2、3sum
而双指针法一定要排序,一旦排序之后原数组的索引就被改变了。
用哈希解法去重很复杂,需要用双指针法。
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
### 1、排序
result = []
#nums = [-1,0,1,2,-1,-4]
sorted_nums = sorted(nums)
### 2、判断最小的数是否就大于0了
if sorted_nums[0] > 0:
print(result)
### 3、滑动窗口法解决
## 差点忘了这一步,记得先for后while
## i left right
for i in range(len(sorted_nums)):
if (sorted_nums[i] > 0):
return result #第一个数是否大于0
if ( i>0 and sorted_nums[i] == sorted_nums[i-1]): #注意 nums[i]nums[i+1]和nums[i]nums[i-1]不一样
continue #去重
left = i + 1
right = len(sorted_nums)-1 #记得写在里面才会更新
while left < right:
if sorted_nums[i]+sorted_nums[left]+sorted_nums[right]==0: #记录答案组
#这里result数组也不会添加
#result.append(sorted_nums[i],sorted_nums[left],sorted_nums[right])
result.append([sorted_nums[i],sorted_nums[left],sorted_nums[right]])
# 跳过相同的元素以避免重复,这一步忘了,还有这个判断去重是right和left分别
while right > left and sorted_nums[right] == sorted_nums[right - 1]:
right -= 1
while right > left and sorted_nums[left] == sorted_nums[left + 1]:
left += 1
left += 1
right -= 1
elif sorted_nums[i]+sorted_nums[left]+sorted_nums[right]>0:
right -= 1
else:
left += 1
return result
3、4sum
待补充
nsum都是这个解法:
n层for循环,最后移动left和right
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
result = []
for i in range(n):
if nums[i] > target and nums[i] > 0 and target > 0:# 剪枝(可省)
break
if i > 0 and nums[i] == nums[i-1]:# 去重
continue
for j in range(i+1, n):
if nums[i] + nums[j] > target and target > 0: #剪枝(可省)
break
if j > i+1 and nums[j] == nums[j-1]: # 去重
continue
left, right = j+1, n-1
while left < right:
s = nums[i] + nums[j] + nums[left] + nums[right]
if s == target:
result.append([nums[i], nums[j], nums[left], nums[right]])
while left < right and nums[left] == nums[left+1]:
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
left += 1
right -= 1
elif s < target:
left += 1
else:
right -= 1
return result
15. 287. Find the Duplicate Number 跟6有点像,都是找重复
a lot of solutions:LeetCode - The World's Leading Online Programming Learning Platform
class Solution(object):
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums.sort()
for i in range(len(nums)):
if nums[i] == nums[i-1]:
return nums[i]
return len(nums)
use sort
16. 回溯算法-子集问题LeetCode - The World's Leading Online Programming Learning Platform
跟之前题目有个好像
DFS和回朔:代码随想录
回溯算法:backtracking algorithm
大家可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。
# 模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
16.1
78. Subsets
回溯算法:backtracking - 有recursive and for cycle
暴力解法/穷举法Exhaustive method
1、组合 代码随想录
解决了n个数中求k个数的组合问题
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
result = [] # 存放结果集
self.backtracking(n, k, 1, [], result)
return result
def backtracking(self, n, k, startIndex, path, result):
if len(path) == k:
result.append(path[:]) # ?存入一个新的空的path[]
return
for i in range(startIndex, n + 1): # 需要优化的地方
path.append(i) # 处理节点
self.backtracking(n, k, i + 1, path, result)
path.pop() # 回溯,撤销处理的节点
剪枝:pruning
2、组合三
加了一个sum值
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
result = [] # 存放结果集
self.backtracking(n, k, 0, 1, [], result)
return result
def backtracking(self, targetSum, k, currentSum, startIndex, path, result):
if currentSum > targetSum: # 剪枝操作
return # 如果path的长度等于k但currentSum不等于targetSum,则直接返回
if len(path) == k:
if currentSum == targetSum:
result.append(path[:])
return
for i in range(startIndex, 9 - (k - len(path)) + 2): # 剪枝
currentSum += i # 处理
path.append(i) # 处理
self.backtracking(targetSum, k, currentSum, i + 1, path, result) # 注意i+1调整startIndex
currentSum -= i # 回溯
path.pop() # 回溯
4、子集1
class Solution:
def subsets(self, nums):
result = []
path = []
self.backtracking(nums, 0, path, result)
return result
def backtracking(self, nums, startIndex, path, result):
# 这里之前是需要if n == sum 才收集这个接受
result.append(path[:]) # 收集子集,要放在终止添加的上面,否则会漏掉自己
# if startIndex >= len(nums): # 终止条件可以不加
# return
for i in range(startIndex, len(nums)):
path.append(nums[i])
self.backtracking(nums, i + 1, path, result)
path.pop()
5、子集2:
和上一题的区别是,上一题子集中题目没有给有重复元素,但是这题可以有重复元素。
like [1,2] and [1,2,2]
重点在于去重
Remove duplicates:if ( i > 0 && nums[i] == nums[i-1] && used[i-1] == 0)
为什么used[ i - 1] 要false或者==0呢,因为前一个一样的元素已经被用过一遍了
class Solution(object):
def subsetsWithDup(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
path = []
nums.sort()
# 忘记了 初始化 used
used = [False] * len(nums)
# 记得startIndex = 0
self.backtracking(nums, 0, used, path, result)
return result
def backtracking(self, nums, startIndex, path, result):
result.append(path[:])
for i in range(startIndex, len(nums)):
if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:
continue
path.append(nums[i])
used[i] = True
self.backtracking(nums, i + 1, used, path, result)
used[i] = False
path.pop()
17.
kind like 20 有效的括号,括号匹配问题,但是不是
用回溯backtracking 理解起来有点困难。。LeetCode - The World's Leading Online Programming Learning Platform
思路:left brackets and right brackets
- The idea is to add
')'
only after valid'('
- We use two integer variables
left
&right
to see how many'('
&')'
are in the current string - If
left < n
then we can add'('
to the current string - If
right < left
then we can add')'
to the current string
class Solution(object):
def generateParenthesis(self, n):
"""
:type n: int
:rtype: List[str]
"""
def dfs(left,right,string):
if len(string) == n * 2:
result.append(string)
return
if left < n:
dfs(left+1, right, string + '(')
if right < left:
dfs(left, right+1, string + ')')
# 这里要注意,在主函数里定义函数
result = []
dfs(0,0,'')
return result
18.
有要求:线性以及不额外使用空间
LeetCode - The World's Leading Online Programming Learning Platform
位运算 - 记得查一下是什么 Bitwise operation
class Solution:
def singleNumber(self, nums: List[int]) -> int:
ones = 0
twos = 0
for num in nums:
ones ^= (num & ~twos)
twos ^= (num & ~ones)
return ones
a. ones = (ones ^ i) & (~twos);
:
ones ^ i
XORs the current numberi
with the previous value ofones
. This operation toggles the bits that have appeared an odd number of times, keeping the bits that have appeared twice unchanged.(~twos)
negates the bits intwos
, effectively removing the bits that have appeared twice from consideration.- The
&
operation ensures that only the bits that have appeared once (after XOR) and not twice (after negatingtwos
) are retained.
The bitwise exclusive OR operator (^) is a binary operator that compares each bit of its first operand to the corresponding bit of its second operand. The result bit is set to 1 if exactly one of the corresponding bits in the two operands is 1. The result bit is set to 0 if both corresponding bits in operands are the same 1.
Here are some examples:
0b1010 ^ 0b1100
is equivalent to0b0110
in binary, which is6
in decimal.0b1111 ^ 0b0000
is equivalent to0b1111
in binary, which is15
in decimal.0b10101010 ^ 0b01010101
is equivalent to0b11111111
in binary, which is255
in decimal.
~ | complement | unary | Flips the bits in the operand. Similar to negation. (All 1's become 0's, and all 0's become 1's). |
19.
动态规划 dynamic programming
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
这个是一个背包问题:
又分为0-1背包 and 完全背包
待补充,因为这里要看完零钱2https://programmercarl.com/0518.%E9%9B%B6%E9%92%B1%E5%85%91%E6%8D%A2II.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
20.
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix or not matrix[0]:
return False
m = len(matrix[0]) # gives the length (number of columns) of the first row of the 2D matrix.
n = len(matrix) # means Number of rows
# attention: they are not the binary search argument but are the virtual flatten argument
# then it is the binary search argument
left = 0
right = m*n - 1
# attention! this right means the index of last element but the len(matrix) means the Number of rows of the matrix
while(left < right):
mid = (left+right) // 2
# 这里不是n//m n%m 是mid,为什么是mid呢。这句话就是在找这个矩阵里的mid在那里
if matrix[mid//m][mid%m] < target:
left = mid + 1
else:
right = mid
"""elif matrix[mid//m][mid%m] < target:
right = mid
else:
return True"""
return matrix[right//m][right%m] == target
LeetCode - The World's Leading Online Programming Learning Platform
21.
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组
# 暴力法: 两个for
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
i = 0
l = len(nums)
while i < l:
if nums[i] == val:
# 暴力法要两个for循环的,不光是把当前这个元素后移,其他后面的元素都需要后移
#nums[i] = nums[i+1]
for j in range(i+1, l):
nums[ j - 1 ] = nums[ j ]
# 记得找到之后还要把l缩短的,因为我们已经找到一个val了
l -= 1
# 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
i -= 1
i += 1
return l
# 双指针:快慢指针
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
slow = 0
fast = 0
l = len(nums)
# 这里不是慢指针控制循环,是快指针,因为快指针遍历,慢指针收集
while (fast < l):
if (nums[fast] != val): # 这里不是 == / 是 !=
#fast += 1
nums[slow] = nums[fast]
slow += 1
#l -= 1
#slow += 1
fast += 1
return slow