Things you need to know about testing & testing interviews - Algorithms (LeetCode_Python)

LeetCode.Sum of two numbers

topic

Given an integer array nums and a target value target, find the two integers in the array whose sum is the target value, and return their array subscripts. The same elements in this array cannot be reused.

Example:

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

Problem-solving ideas:

Create an empty dictionary, store the difference between the target value and the values ​​in the nums list in the dictionary, and compare it with other values.

The key in the dictionary corresponds to the difference between the target value and the list value ( is target - nums[i]) , and the value of the dictionary corresponds to the index position i of the current nums[i].

If nums[i] is in the dictionary, (Note: i is a changing value. In order to prevent confusion with the previous one, the previous "target - nums[i]" is written "target - nums[k]" to distinguish ), that is to say target - nums[k] = nums[i] ( indicates that the previous dictionary stores Among the keys, there is a value equal to the current nums[i]), then the corresponding value of target - nums[k] in the dictionary is returned, that is, the value of nums[k] Index position k, and index position i of the current nums[i]. Both are the required results.

The code is implemented as follows:

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        # 创建空字典
        # 存储目标值与 nums 列表其中一个数值之差,同时与其他数值进行比对
        # 相等返回对应的索引
        auxiliary_dict = {}

        # 获取 nums 列表的长度
        nums_len = len(nums)

        for i in range(nums_len):
            # 目标值与对应 nums 列表 i 索引中的数值之差
            two_sub = target - nums[i]
            # 如果 nums[i] 在 auxiliary_dict 列表中,返回对应的索引
            # 这里 nums[i] 是变化的,i 值不断变化。此时的 num[i] 如果在字典中,表示前面某次当中,目标值与其中一个数值之差等于当前的 num[i]
            if nums[i] in auxiliary_dict:
                return auxiliary_dict[nums[i]], i

            # 否则,往字典中添加键值对
            auxiliary_dict[two_sub] = i

LeetCode.Number of palindromes

topic

Determine whether an integer is a palindrome. A palindrome number is an integer that reads the same in forward order (from left to right) and reverse order (from right to left).

Example 1:

输入: 121
输出: true

Example 2:

输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

Example 3:

输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。

Problem-solving ideas:

  1. The first method is to convert the number into a string and determine whether the string is a palindrome number, but extra space needs to be created in the middle.
  2. The second method, consider directly inverting the number and comparing it with the original number. Integer overflow may occur in the middle.
  3. Under the premise of the second method, consider dividing the number into two parts before and after, inverting the latter part and comparing it with the previous part.

The implementation code is as follows:

class Solution:
    def isPalindrome(self, x: int) -> bool:
    	'''判断数字是否是回文数
		
		Args:
		    x: 传入的待判断的数字
		
		Returns:
		    返回是否是回文数的判断结果,结果类型为布尔型
    	'''
        # 首先负数不是回文数,
        # 当传进来的数字非负,但最后一位数为 0 时,
        # 只有当数字为 0,才符合回文数的要求。
        if (x < 0 ) or (x != 0 and x % 10 == 0):
            return False
        
        # 将传入的数字分为前后两部分,
        # 将后半部分进行倒序,与前面部分进行比较,
        # 相等则为回文数,否则不是回文数。
        cur = 0  # 用于存储后半部分数字
        while (x > cur):
            cur = cur * 10 + x % 10
            x //= 10
        
        # 考虑数字位数为奇数的情况下,可以用 cur // 10 进行消除中间数
        return (x == cur) or (x == (cur // 10))

LeetCode.Valid parentheses

topic

Given a  string that only includes '(',')','{','}','[',']' , determine whether the string is valid.

A valid string must satisfy:

  1. The opening bracket must be closed by a closing bracket of the same type.
  2. Opening brackets must be closed in the correct order.

Note that the empty string is considered a valid string.

Example 1:

输入: "()"
输出: true

Example 2:

输入: "()[]{}"
输出: true

Example 3:

输入: "([)]"
输出: false

Example 4:

输入: "{[]}"
输出: true

Problem-solving ideas

  1. Thoughts: Path;
  2. Map the brackets, the right bracket is the key, and the left bracket is the value;
  3. If a left parenthesis is encountered, push it directly onto the stack. Wait for subsequent matching processing;
  4. If a closing parenthesis is encountered, the top element of the stack is checked. If they are of the same type, a pop-up will pop up to continue processing the next part. Otherwise, return False directly;
  5. If there are still elements on the stack after the final traversal is completed, False will also be returned.

The code is implemented as follows:

class Solution:
    def isValid(self, s: str) -> bool:
        '''判断是否是有效的括号

        Args:
            str: 包含括号的字符串
        
        Returns:
            返回判断的结果,满足条件:
                1. 左括号必须用相同的类型的右括号闭合。
                2. 左括号必须以正确的顺序闭合。
            空字符串可以被认为是有效的字符串
            返回类型为布尔型
        '''
        # 以栈形式存储左括号
        stack = []

        # 以右括号当成键映射对应类型的左括号
        prths_mapping = {'}': '{', ']': '[', ')': '('}

        # 遍历字符串,遇左括号则进行入栈
        for ch in s:
            # 对字符进行判断,是否为右括号
            if ch in prths_mapping:
                # 为右括号的情况下,判断 stack 栈顶是否是同类型的左括号
                # pop 出栈顶的字符
                # 若 stack 为空,用 '?' 进行标记
                pop_prth = stack.pop() if stack else '?'

                # 如果左右括号不成对,直接返回 False
                if prths_mapping[ch] != pop_prth:
                    return False
            else:  # 左括号入栈
                stack.append(ch)
        # stack 最终为空,则表示为有效
        return not stack

LeetCode.Merge two ordered linked lists

topic

Merge two sorted linked lists into a new sorted linked list and return. The new linked list is formed by concatenating all the nodes of the two given linked lists.

Example:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

Problem-solving ideas

  1. Set the "sentinel node" to correctly return the merged linked list;
  2. Control the cur pointer and adjust its next pointer;
  3. Compare the node sizes of the two linked lists and connect the smaller node after the cur node;
  4. The loop operation terminates when one of the linked lists is empty;
  5. If the loop ends and one of the linked lists is not empty, the remaining parts are appended to the merged linked list (because both linked lists are ordered, the remaining parts are larger than the elements of the merged linked list;
  6. Finally, the merged linked list is returned.

The code is implemented as follows:

# # Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        '''将两个有序链表合并成一个链表然后返回

        Args:
            l1: 有序链表 1
            l2: 有序链表 2
        
        Returns:
            返回合并后的有序链表
        '''
         # 定义一个哨兵节点,用以正确返回合并后的链表
        pre_head = ListNode(None)

        # 控制 cur 指针,比较节点大小
        cur = pre_head

        # 比较两个链表的节点大小,当两个链表任意一个为空,则终止
        while l1 and l2:
            # 当 l1 的节点较小,则指针指向 l1,同时向后移
            if l1.val < l2.val:
                cur.next, l1 = l1, l1.next
            else:  # 否则,指针指向 l2,同时向后移
                cur.next, l2 = l2, l2.next
            # 维护 cur 指针
            cur = cur.next
        # 考虑其中任意一个链表为空,将非空的链表拼接在合并链表后面
        cur.next = l1 if l1 else l2
        return pre_head.next

LeetCode.Merge two sorted arrays

topic

Given two ordered integer arrays nums1 and nums2, merge nums2 into nums1 so that num1 becomes an ordered array.

illustrate:

Initialize nums1 and nums2 with m and n elements respectively.

You can assume that nums1 has enough space (space size greater than or equal to m + n) to hold the elements in nums2.

Example:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

输出: [1,2,2,3,5,6]

Problem-solving ideas

  1. Use the double pointer method to traverse from the back to the front
  2. Definition: p1 pointer points to the end of num1 number, p2 points to the end of num2 number, and p points to the end of num1;
  3. Loop through from back to front to compare the size of elements between two arrays;
  4. When p < 0, that is, one of p1 and p2 is less than 0, the traversal ends;
  5. If there is a remaining part of the num2 array, because the arrays are all ordered, directly put the remaining part of the num2 array into the corresponding position of the num1 array.

The code is implemented as follows:

class Solution:
    def merge(self, nums1, m: int, nums2, n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        
        合并两个有序数组为一个有序数组

        Args:
            num1: 有序数组 1
            m: num1 的元素数量
            num2: 有序数组 2
            n:num2 的元素数量
        
        Returns:
            返回合并后的有序数组
        """
        # 通过双指针的方法,从后向前遍历的方法、
        # 定义指针 p1 指向 num1 的数字末尾
        # 定义指针 p2 指向 num2 的数字末尾
        # 定义指针 p 指向 num1 的最末尾
        p1 = m - 1
        p2 = n - 1
        p = m + n - 1
        # 当 p 小于 0,即是 p1 和 p2 其中一个小于 0,遍历结束
        while p1 >= 0 and p2 >= 0:
            if nums1[p1] < nums2[p2]:
                nums1[p] = nums2[p2]
                p2 -= 1
            else:
                nums1[p] = nums1[p1]
                p1 -= 1
            p -= 1
        # 两个数组都是有序的
        # 若是 p1 先小于 0,将 num2 剩余部分放在 num1 数组前面
        nums1[:p2 + 1] = nums2[:p2 + 1]

LeetCode.Reverse linked list

topic

Reverse a singly linked list.

Example:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

Problem-solving ideas

  1. Iterate. Use double pointers;
  2. defines two pointers, one pre points to None, and one cur points to the head of the linked list;
  3. Traverse the linked list, point the next pointer of the current node to pre, and at the same time pre and cur The pointers all advance one bit (pay attention to saving elements here)
  4. When cur is None, the iteration is completed. pre now points to the head of the linked list and returns.

The code is implemented as follows:

# 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:
        '''反转链表

        Args:
            head: 链表
        
        Returns:
            返回反转后的链表
        '''
        # 定义两个指针
        # pre 指向 None,cur 指向原链表头部
        pre = None
        cur = head
        # cur 为 None,迭代结束
        while cur:
            # 这里注意引用更改,节点的存储
            # 下面的代码相当于
            # 存储节点值
            # tmp = cur.next
            # 将 cur 的 next 指向 pre
            # cur.next = pre
            # 移动两个指针
            # pre = cur
            # cur = tmp
            cur.next, pre, cur = pre, cur, cur.next
        # 返回反转后的链表
        return pre

LeetCode.Longest palindrome string

topic

Given a string containing uppercase and lowercase letters, find the longest palindrome constructed from these letters.

During construction, be aware of case sensitivity. For example, "Aa" cannot be treated as a palindrome string.

Note:
assumes that the length of the string will not exceed 1010.

Example:

输入:
"abccccdd"

输出:
7

解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

Problem-solving ideas

The concept of palindrome string: it is a string that reads the same forward and backward.

For example: abba, this string is a palindrome string, and the center limit is the position of the vertical line in the middle of ab|ba. abdba, and this string is also a palindrome string, with the center limit at the position of character d in ab(d)ba.

Here we can see that the number of characters forming a palindrome string may be an odd number or an even number.

When the number of characters that make up a palindrome string is an even number, the characters must appear in pairs (such as abba, all exist in pairs); when the number of characters that make up a palindrome string is an odd number, the middle characters must be removed. The central character and other characters also exist in pairs. (For example, abdba removes the central character d, and other characters are also in pairs)

However, it should be noted that when the number of characters given in the question is an odd number, it does not mean that it cannot be used to construct a palindrome string. As long as one is removed and becomes an even number, it can also be constructed. Palindrome string.

When the number of a certain character is an odd number, one of them can be retained without being eliminated and used as the center of the palindrome string. Therefore, it is necessary to add the retained character after the paired characters form the palindrome string depending on the situation. Go in. If the characters are all in pairs, there is no need to consider this situation.

The code is implemented as follows:

class Solution:
    def longestPalindrome(self, s: str) -> int:
        from collections import Counter
        # 导入 Counter 类,用以统计字母出现的次数
        d = Counter(s)

        ans = len(s)
        # 统计字母出现次数为奇数有多少
        odd = 0

		# 遍历字母对应的个数
        for value in d.values():
        	# 统计字母出现次数为奇数有多少
        	# 先对符合条件的进行统计 + 1
            if value % 2 != 0:
                odd += 1
		# 当 odd 为 0 的情况下
		# 也就是所有字符都成对存在的情况下,直接返回题目所给字符的长度即可
		# 若 odd 不为 0,也就是有出现字母个数为奇数的情况下,
		# 这里的思路是将所有的字符都添加进来,字符出现次数为奇数的情况,进行统计
		# 将这些情况全部剔除,但同时需要保留 1 个字符作为中心,所以最后要 + 1       
        return ans if odd == 0 else ans - odd + 1

LeetCode. Remove duplicates in sorted array

topic

Given a sorted array, you need to remove duplicate elements in place so that each element appears only once, and return the new length of the array after removal.

Instead of using extra array space, you must modify the input array in-place and do it using O(1) extra space.

Example 1:

给定数组 nums = [1,1,2], 

函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 

你不需要考虑数组中超出新长度后面的元素。

Example 2:

给定 nums = [0,0,1,1,1,2,2,3,3,4],

函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。

你不需要考虑数组中超出新长度后面的元素。

illustrate:

Why is the returned value an integer but the output answer is an array?

Please note that the input array is passed by "reference", which means that modifications to the input array in the function are visible to the caller.

You can imagine the internal operation as follows:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

Problem-solving ideas

Idea: double pointers

Pay attention here when reviewing the question. It has been stated in the question that the array has been sorted. Based on this premise, we can conclude that if there are duplicates in the array, then the duplicates must be adjacent.

Based on this premise, we initialize two pointers, one at the front and one at the back. The front moves first. If nums[front] == ​​nums[tail], it means that the element value is repeated, and the front moves directly backward.

If nums[front] != nums[tail], it means that the two elements are no longer duplicates. At this time, the element value corresponding to the front pointer is copied to the next element of nums[tail], that is, nums[tail+ 1], and the tail also moves forward.

Repeat the above process until front reaches the end of the array.

The code is implemented as follows:

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        length = len(nums)
        if length == 0:
            return 0
        
        # 初始化双指针
        # front 在前,tail 在后
        tail = 0
        front = 1
        
        # 遍历数组
        while front < length:
            # 如果两指针所指的元素值不相同,
            # 表示元素不重复,
            # 这时候将 nums[front] 的值复制给 nums[tail+1]
            if nums[front] !=  nums[tail]:
                tail += 1
                nums[tail] = nums[front]
            # front 持续移动
            front += 1

        return tail + 1

LeetCode.Full sorting of the list

topic

Given a sequence with no repeating numbers, return all possible permutations of it.

Example:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

Problem-solving ideas

Idea: Deeply optimize search

Let’s look at the question first, taking the full arrangement of the given array [1, 2, 3] as an example:

Starts with 1, the whole arrangement is: [1,2,3], [1,3,2];
Starts with 2, the whole arrangement is [2,1, 3], [2,3,1];
Starting with 3, the whole arrangement is [3,1,2], [3,2,1].
From the above situation, it can be seen. Enumerate the possible situations for each digit. The selected number cannot appear in the following selections. Following this approach, all situations will be listed. This is actually a depth-first search, and the path formed from the root node to the leaf node is a full arrangement.

Following this idea, follow the above example and start with an empty list [], starting with 1 as an example. Now make sure it starts with 1, then the list is [1]. Now choose one of [2] and [3], choose 2 first, and finally only the number 3 is left, so the full arrangement is [1, 2, 3] .

It is known that there is another situation, which is [1, 3, 2], so how to achieve the change from [1, 2, 3] to [1, 3, 2]. How is depth-first search implemented? In fact, when returning from [1, 2, 3] to [1, 2], the number 3 is cancelled. Because the current layer can only select 3, the selection of 2 is cancelled, so that the subsequent program can select 3. You can also choose 2 later.

The code is implemented as follows:

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:

        def _dfs(nums, depth, pmt, be_selected, length, ans):
            # 表示深度优化搜索的深度等于数组长度时,这个时候表示全排列已经生成
            # 也就是符合情况的选择已经选择完毕
            # 将这个全排列的情况添加到列表中
            # 这里需要注意,pmt 在参数传递是引用传递,拷贝一份添加到结果中
            if depth == length:
                ans.append(pmt[:])
                return

            # 开始遍历
            for i in range(length):
                # be_selected,表示原数组中的元素的状态,是否被选择,是为 True,否为 False
                if not be_selected[i]:
                    # 当元素被选择时,改变状态
                    be_selected[i] = True
                    # 将元素添加到 pmt 中,以构成后续
                    pmt.append(nums[i])
                    # 向下一层进行遍历
                    _dfs(nums, depth + 1, pmt, be_selected, length, ans)
                    # 遍历结束时,进行回溯,这个时候状态要进行重置
                    # 如上面说的 `[1, 2, 3]` 到 `[1, 3, 2]` 中变化,要撤销 3,再撤销 2,重新选择
                    # 状态改变
                    be_selected[i] = False
                    # 撤销
                    pmt.pop()

        length = len(nums)
        if length == 0:
            return []

        be_selected = [False] * length
        ans = []
        _dfs(nums, 0, [], be_selected, length, ans)
        return ans

LeetCode. Number of numbers that appear once in the array 

topic

Except for two numbers in an integer array nums, all other numbers appear twice. Please write a program to find these two numbers that only appear once. The required time complexity is O(n) and the space complexity is O(1).

Example 1:

输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

Example 2:

输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

Problem-solving ideas

Idea: XOR, bit operation

Let’s first talk about the properties of XOR: if the binary bits are the same, it is 0, if they are different, it is 1.

Let’s talk about the rules of XOR:

If the two values ​​are the same, the XOR result of the two is 0, (that is, the XOR result of any number with itself is 0)
The XOR result of any number with 0 is itself.
Simultaneous XOR satisfies commutative law and associative law (mathematical conformity: ⊕)

Commutative law: a ⊕ b = b ⊕ a
Associative law: a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c
Come back and look at this question. The description of the question is, [In the integer array nums, except for two numbers, all other numbers appear twice]. Then according to the commutative law and the associative law, if the same numbers are XORed, then the same numbers will become 0, and according to the second law, the remaining numbers will appear once.

The code is implemented as follows:

class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        res = 0
        # 全员进行异或
        for num in nums:
            res ^= num
        
        # 找出不为 0 的最低位
        # & 位运算的使用
        div = 1
        while (div & res == 0):
            div <<= 1
        
        # 进行分组
        p, q = 0, 0
        for num in nums:
            if num & div:
                p ^= num
            else:
                q ^= num
            
        return [p, q]

LeetCode. A set of K flip linked lists

topic

You are given a linked list, and each group of k nodes is flipped. Please return the flipped linked list.

k is a positive integer whose value is less than or equal to the length of the linked list.

If the total number of nodes is not an integer multiple of k, then keep the last remaining nodes in their original order.

Example:

给你这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5

illustrate:

  • Your algorithm can only use a constant amount of extra space.
  • You can't just change the value inside the node, you need to actually swap the node.

Problem-solving ideas

Idea: Iterate and flip the linked list

  1. First, ensure the range of flipping, which is controlled by the k mentioned in the question;
  2. Regarding the flipping of the linked list, we should pay attention to the issues of predecessor and successor to prevent pointing errors. This is also to connect the flipped linked list with the subsequent one;
  3. Define pre and tail, pre represents the precursor of the part of the linked list to be flipped, and tail represents the end;
  4. The tail above reaches the end via k control;
  5. Flip the linked list and splice the flipped part with the subsequent part;
  6. Note: According to the meaning of the question, when the length of the flipped part is less than k, no processing is performed at this time.

The code is implemented as follows:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        if head == None and head.next == None and k < 2:
            return head
        # 定义哨兵节点
        dummy = ListNode(0)
        # 指向节点
        dummy.next = head

        # 定义前驱后继节点
        pre = dummy
        tail = dummy

        # 控制 tail 到待翻转链表部分的末尾
        while True:
            count = k
            while count > 0 and tail != None:
                count -= 1
                tail = tail.next
            # 到达尾部时,长度不足 k 时,跳出循环
            if tail == None:
                break

            # 这里用于下次循环
            head = pre.next
            # 开始进行翻转
            while pre.next != tail:
                tmp = pre.next
                pre.next = tmp.next
                tmp.next = tail.next
                tail.next = tmp
            
            # 重置指针
            pre = head
            tail = head
        
        return dummy.next

LeetCode. A number that appears only once 

topic

Given a non-empty array of integers, each element appears twice except for one element which appears only once. Find the element that appears only once.

illustrate:

Your algorithm should have linear time complexity. Can you do it without using extra space?

Example:

输入: [4,1,2,1,2]
输出: 4

Problem-solving ideas

Idea: bit operations

Before explaining the implementation of the bit operation method, let’s take a look at the question first. After the explanation, the question requires [The algorithm should have linear event complexity and no additional space is required a>]. If there is no such requirement, we can think of the following methods:

  1. Use set storage and traverse the array. When the number is not in the set, it is added to the set first. When the number exists, it is deleted from the set. Because the question has stated that if there is only one number that is repeated, then the final set The remainder is that number.
  2. Use a hash table to store numbers and the number of times they appear, traverse the array, and maintain the hash table. Finally, the hash table is traversed, and the number with a number of occurrences of 1 is the obtained number.
  3. (This idea comes from the official solution). Sets are also used to store numbers, but ordinary operations are involved here. The set stores the elements of the array, because there will be no duplicate numbers in the set, and only one number in the array is repeated. When twice the sum of the numbers in the set minus the sum of all the elements in the original array, then the two The result is this number.

All the above methods can solve this problem, but the question requires [the algorithm should have linear event complexity and no additional space is required]. Then none of these three methods meet the conditions.

Regarding the use of bit operations, let’s talk about the properties of XOR again: if the same binary bit is the same, it will be 0, and if it is different, it will be 1. Regarding the rules of XOR:

The result of any number XORed with itself is 0.
The result of any number XORed with 0 is itself.
At the same time, XOR satisfies the commutative law and associative law (mathematical symbol: ⊕)

Commutative law: a ⊕ b = b ⊕ a
Associative law: a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c
First define the return variable as 0, and perform XOR on the array variables in sequence. Then according to the above rules, we can calculate the non-repeating number mentioned in the question.

The code is implemented as follows:

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        # 任何数与 0 异或结果为自身
        # 这里定义变量 0,对数组所有元素进行异或时
        # 任何数与自身异或结果为 0
        # 那么最终剩下的就是单独的数字
        res = 0
        for x in nums:
            res ^= x
        return res

LeetCode. Find duplicate numbers

topic

Given an array nums containing n + 1 integers, all numbers between 1 and n (inclusive), we know that there is at least one duplicate integer. Suppose there is only one repeated integer, find this repeated number.

Example:

输入: [1,3,4,2,2]
输出: 2

illustrate:

  • The original array cannot be changed (assuming the array is read-only).
  • Only extra O(1) space can be used.
  • The time complexity is less than O(n2).
  • There is only one repeated number in the array, but it may appear more than once.

Problem-solving ideas

Idea: binary search

It should be noted here that there are 4 tips as stated in the question. Some methods will be restricted here, such as:

Sort the array, and the duplicate numbers are adjacent. Based on this, you can find the duplicate number (this violates [cannot change the original array])
Use a hash table (this violates [only] Can use additional O(1) algorithm])

The above method can be used without restrictions, but here, due to the problem Restrictions are given, so they are not considered for now.

Let’s look at this question first, [Given an array nums containing n + 1 integers, the numbers are all between 1 and n (including 1 and n)], this is the premise given in the question.

Based on this premise, the idea of ​​​​dichotomy here is to first determine a value (the middle value mid of [left, right] is also determined here), but what is counted here is the number of elements in the original array that are less than or equal to the value of mid ( Here it is defined as count). If this count is strictly greater than the value of mid, the repeated element will fall in the interval [left, mid].

A principle is involved here:The drawer principle. Regarding the drawer principle, it is roughly like this: if there are ten apples on the table, we need to put these ten apples into nine drawers. No matter how we put them, we will find that there will be at least one drawer with no less than two apples in it. apple.

Let’s conduct an analysis based on Example 1 given in the question:

[1,3,4,2,2]
1

First, we know that the value 2 here is a duplicate value. Now, let’s analyze it according to the above ideas.

There are 5 numbers here, that is, n + 1 = 5, n = 4, then the values ​​in the array here are all between 1 and 4.

Now set a value (based on the intermediate value mid mentioned above), here it is set to 2, traverse the array, and count the number of numbers less than or equal to 2. Here you can see that there are 3 values, which are strictly greater than mid, so the repeated values ​​fall in the interval [1, 2].

The code is implemented as follows:

class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        size = len(nums)

        left = 1
        right = size - 1

        while left < right:
            # 先找中间值
            mid = left + (right - left) // 2
            # mid = (left + right) // 2
            # 遍历数组
            # 统计数组中小于等于中间值的元素个数
            count = 0
            for num in nums:
                if num <= mid:
                    count += 1
            
            # 如果统计数严格大于中间值时,那么重复值将落在 [left, mid] 这个区间
            if count > mid:
                # 将右边界缩小到 mid
                right = mid
            # 否则重复值落在 [mid + 1, right]
            else:
                left = mid + 1
        return left

LeetCode. Longest valid bracket

topic

Given a string containing only ‘(’ and ‘)’, find the length of the longest substring containing valid parentheses.

Example:

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

Problem-solving ideas

Idea: stack

In the question, to find valid brackets, you may need to expand from the inside out, which is in line with the first-in-last-out characteristic of the stack.

Let's first use brute force solution to try to solve this problem.

Valid parentheses appear in pairs, so we try to list all possible non-empty even-length substrings to determine whether they are valid.

When we encounter a left bracket (, we push it onto the stack. When we encounter a right bracket), pop a left bracket () from the stack. If there is no left bracket on the stack, or there are still elements on the stack after the traversal is completed , then this substring is invalid. Loop through and update the maximum length.

The code is implemented as follows:

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        max_len = 0
        stack = []
        # 当先遇到 `)` 需要先弹出元素,这里可以防止报错
        # 当遇到的 `()` 的字符时,-1 在计算长度的时候,发挥作用
        stack.append(-1)
        for i in range(len(s)):
            if s[i] == '(':
                stack.append(i)
            else:
                stack.pop()
                if not stack:
                    stack.append(i)
                else:
                    max_len = max(max_len, i - stack[-1])
        return max_len

LeetCode. Determine whether there is a cycle in the linked list

topic

Given a linked list, determine whether there is a cycle in the linked list.

To represent a cycle in a given linked list, we use the integer pos to represent the position in the linked list where the tail of the linked list is connected (indexing starts at 0). If pos is -1, then there is no cycle in the linked list.

Example 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

Example 2:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

Problem-solving ideas

Idea: Hash table, fast and slow pointers
Here, we look directly at the example. If there is a loop in the linked list, then a certain node will be visited more than once.

Hash table
Then, we use the hash table to store the visited nodes. The interpretation basis is as follows:

When a node is accessed and is found to exist in the hash table, then we can determine that the linked list is a circular linked list.
Otherwise, continue accessing until the node is empty.

Fast and Slow Pointers
The last advanced part of the question asks whether the problem can be solved with constant space complexity. Because of the previous approach, defining the hash table storage requires additional space.

Here, we use the idea of ​​​​fast and slow pointers to solve the problem. details as follows:

Define two pointers p and q. One of the fast pointers p moves two steps at a time, and the slow pointer q moves one step at a time;
If there is no cycle, then the fast pointer will If we reach the end first, we can return False;
If there is a loop, the fast pointer will reach a node in the linked list again, and eventually the fast and slow pointers will overlap and return True.

The code is implemented as follows:

# 哈希表
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        hash_map = {}
        
        # 结点非空时
        while head:
            # 先判断结点是否已经存在于哈希表中
            # 存在,则表示存在环
            if head in hash_map:
                return True
            # 记录访问的节点,访问过都标记为 1
            hash_map[head] = 1
            head = head.next
        
        return False

# 快慢指针
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        # 定义快慢指针
        # 快指针 p 每次移动两步,慢指针 q 每次移动一步
        p = head
        q = head
        
        while p and p.next:
            q = q.next
            p = p.next.next
            if p == q:
                return True
        return False

Guess you like

Origin blog.csdn.net/weixin_73348410/article/details/129704842