刷题记录6天题打卡

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 where 0 <= i < n.
  • abs(nums[i] - nums[i+1]) <= 1 where 0 <= i < n-1.
  • The sum of all the elements of nums does not exceed maxSum.
  • 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.

2762. Continuous Subarrays

滑动窗口和一个数据类型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
  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.

  2. Inside the loop, it checks whether the index at the front of maxQ (maxQ[0]) is less than the index at the front of minQ (minQ[0]). This is to determine which end of the subarray has a value that contributes more to the excess difference. If maxQ[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.

  3. If maxQ[0] < minQ[0], it increments the left boundary by one and removes the leftmost element from maxQ using maxQ.popleft(). This operation effectively shifts the left boundary of the subarray to the right by one element.

  4. If maxQ[0] >= minQ[0], it means the minimum value is further to the left, so it increments the left boundary by one and removes the leftmost element from minQ using minQ.popleft().

3.

561. Array Partition

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.

316. Remove Duplicate Letters

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.

532. K-diff Pairs in an Array

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.

767. Reorganize String

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.

​​​​​​202. Happy Number

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.

617. Merge Two Binary Trees

合并二叉树

二叉树集合:

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. 

22. Generate Parentheses

kind like 20 有效的括号,括号匹配问题,但是不是

用回溯backtracking 理解起来有点困难。。LeetCode - The World's Leading Online Programming Learning Platform

思路:left brackets and right brackets

  1. The idea is to add ')' only after valid '('
  2. We use two integer variables left & right to see how many '(' & ')' are in the current string
  3. If left < n then we can add '(' to the current string
  4. 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.

137. Single Number II

有要求:线性以及不额外使用空间

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 number i with the previous value of ones. 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 in twos, 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 negating twos) 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 to 0b0110 in binary, which is 6 in decimal.
  • 0b1111 ^ 0b0000 is equivalent to 0b1111 in binary, which is 15 in decimal.
  • 0b10101010 ^ 0b01010101 is equivalent to 0b11111111 in binary, which is 255 in decimal.
~complementunaryFlips the bits in the operand.  Similar to negation.  (All 1's become 0's, and all 0's become 1's).

19.

322. Coin Change

动态规划 dynamic programming

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导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.

74. Search a 2D Matrix

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.

27. Remove Element

不要使用额外的数组空间,你必须仅使用 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值