数组试题(Python实现)

目录

1. 两数之和(Hashmap)

2. 三数之和(三指针法)

3. 第 k 个缺失的正整数

4. 连续子数组的最大和(DP)

5. 最长无重复子数组(滑动窗口)

6. 滑动窗口的最大值

7. 盛水最多的容器(双指针)

8. 接雨水问题(双指针)

9. 合并两个有序数组

10. 合并区间 力扣(LeetCode)

11. 两个数组的交集

12. 寻找两个正序数组的中位数

13. 二分查找

14. 旋转数组的最小数字(二分查找)

15. 二维数组中的查找(二分查找)

16. 寻找峰值(二分)

17. 数组中的逆序对

18. 数组的全排列(递归)

19. 没有重复项数字的全排列

20. 有重复项数字的全排列

21. 数组中出现次数超过一半的数字(哈希Map记录出现次数)

22. 数组中只出现一次的两个数字(哈希Map记录出现次数)

23. 缺失的第一个正整数(哈希Map记录出现次数)


1. 两数之和(Hashmap)

class Solution:
    def twoSum(self , numbers: List[int], target: int) -> List[int]:
        res = []
        map = dict()
        for i in range(len(numbers)):
            tmp = target - numbers[i]
            if tmp not in map:
                map[numbers[i]] = i
            else:
                res.append(map[tmp] + 1)
                res.append(i + 1)
                break
        return res

2. 三数之和(三指针法)

i、left、right三个指针当作第一个值遍历数组,left 和 right 前后指针遍历查找

class Solution:
    def threeSum(self , num: List[int]) -> List[List[int]]:
        res = []
        if len(num) < 3: return res
        num.sort()
        # i 从 0 下标到 len-3
        for i in range(len(num)-2):
            # 避免首元素重复
            if i > 0 and num[i] == num[i-1]:
                continue
            l = i + 1
            r = len(num) - 1
            while l < r:
                if num[i] + num[l] + num[r] < 0:
                    l += 1
                elif num[i] + num[l] + num[r] > 0:
                    r -= 1
                else:
                    res.append([num[i], num[l], num[r]])
                    while l+1 < r and num[l] == num[l+1]:
                        l += 1
                    while l+1 < r and num[r] == num[r-1]:
                        r -= 1
                    l += 1
                    r -= 1
        return res

3. 第 k 个缺失的正整数

大数组存储:空间换时间方法O(n)

class Solution:
    def findKthPositive(self, arr: List[int], k: int) -> int:
        nums = [-1]*(arr[-1]+k)
        for a in arr:
            nums[a-1] = 0
        count = 0
        for i in range(len(nums)):
            if nums[i] != 0:
                count += 1
            if count == k:
                return i+1

set记录已出现的数据O(n)

class Solution:
    def findKthPositive(self, arr: List[int], k: int) -> int:
        sets = set()
        count = 0
        for a in arr:
            sets.add(a)
        for i in range(1, arr[-1]+1):
            if i not in sets:
                count += 1
            if count == k:
                return i
        return arr[-1]-count+k

二分查找O(logn)

class Solution:
    def findKthPositive(self, arr: List[int], k: int) -> int:
        l = 0
        r = len(arr) - 1
        # 当第一个数大于k时,说明第k个缺失的值就是k
        if arr[0] > k:
            return k
        while l < r:
            mid = (l+r)//2
            if arr[mid] - (mid+1) >= k:
                r = mid
            else:
                l = mid + 1
        if arr[r] - (r + 1) >= k:
            return r + k
        else:
            return r + k + 1

4. 连续子数组的最大和(DP)

class Solution:
    def FindGreatestSumOfSubArray(self, array: List[int]) -> int:
        # 记录到下标i为止的最大连续子数组和
        dp = [0 for i in range(len(array))]
        dp[0] = array[0]
        maxsum = dp[0]
        for i in range(1, len(array)):
            # 状态转移:连续子数组和最大值
            dp[i] = max(dp[i - 1] + array[i], array[i])
            # 维护最大值
            maxsum = max(maxsum, dp[i])
        return maxsum

5. 最长无重复子数组(滑动窗口)

class Solution:
    def maxLength(self , arr: List[int]) -> int:
        map = dict()
        res = 0
        left = 0
        for right in range(len(arr)):
            if arr[right] in map:
                map[arr[right]] += 1
            else:
                map[arr[right]] = 1
            # 窗口内有重复则窗口左侧移动
            while map[arr[right]] > 1:
                map[arr[left]] -= 1
                left += 1
            res = max(res, right - left + 1)
        return res

6. 滑动窗口的最大值

class Solution:
    def maxInWindows(self , num: List[int], size: int) -> List[int]:
        res = []
        if size <= 0 or size > len(num): return res
        for i in range(len(num) - size + 1):
            # 寻找每个窗口的最大值
            maxx = 0
            for j in range(i, i + size):
                maxx = max(maxx, num[j])
            res.append(maxx)
        return res

双向队列

from collections import deque
class Solution:
    def maxInWindows(self , num: List[int], size: int) -> List[int]:
        res = []
        if size <= 0 or size > len(num): return res
        # 双向队列
        dq = deque()
        # 遍历第一个窗口
        for i in range(size):
            # 去掉小值
            while len(dq) != 0 and num[dq[-1]] < num[i]:
                dq.pop()
            dq.append(i)
        # 遍历后续数组
        for i in range(size, len(num)):
            res.append(num[dq[0]])
            # 移除上一个窗口中的值
            while len(dq) != 0 and dq[0] < (i - size + 1):
                dq.popleft()
            # 去掉小值
            while len(dq) != 0 and num[dq[-1]] < num[i]:
                dq.pop()
            dq.append(i)
        res.append(num[dq[0]])
        return res

7. 盛水最多的容器(双指针)

class Solution:
    def maxArea(self , height: List[int]) -> int:
        if len(height) < 2: return 0
        res = 0
        left = 0
        right = len(height) - 1
        while left < right:
            capacity = min(height[left], height[right]) * (right - left)
            res = max(res, capacity)
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return res

8. 接雨水问题(双指针)

class Solution:
    def maxWater(self , arr: List[int]) -> int:
        res = 0
        if len(arr) == 0: return res
        left = 0
        right = len(arr) - 1
        maxL = 0
        maxR = 0
        while left < right:
            maxL = max(maxL, arr[left])
            maxR = max(maxR, arr[right])
            # 按较短边界积水,并移动指针
            if maxL < maxR:
                res += maxL - arr[left]
                left += 1
            else:
                res += maxR - arr[right]
                right -= 1
        return res

9. 合并两个有序数组

class Solution:
    def merge(self , A, m, B, n):
        a = m-1
        b = n-1
        for i in range(m+n-1, -1, -1):
            if b < 0 or a >= 0 and A[a]>=B[b]:
                A[i] = A[a]
                a -= 1
            else:
                A[i] = B[b]
                b -= 1
        return A

10. 合并区间 力扣(LeetCode)

入参为单链表:

def merge(nums):
	if len(nums) <= 1: return nums
	res = []
	now = nums[0]
	cur = now
	for i in range(1, len(nums)):
		if nums[i] == cur + 1:
			cur += 1
			continue
		elif now == cur:
			res.append(str(now))
		else:
			res.append(str(now) + '->' + str(cur))
		now = nums[i]
		cur = now
	if nums[-1] == nums[-2]+1:
		res.append(str(now) + '->' + str(cur))
	else:
		res.append(str(nums[-1]))
	return res
nums1 = [0,1,2,4,5,7]
nums2 = [0,2,3,4,6,8,9]
nums3 = []
nums4 = [-1]
nums5 = [0]
print(merge(nums))

入参为嵌套链表:

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key = lambda x: x[0])
        res = []
        res.append(intervals[0])
        for i in range(len(intervals)):
            if res[-1][-1] < intervals[i][0]:
                res.append(intervals[i])
            else:
                res[-1][-1] = max(res[-1][-1], intervals[i][-1])
        return res

11. 两个数组的交集

两个set去重:

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        set1 = set(nums1)
        set2 = set(nums2)
        res = []
        for i in set1:
            if i in set2:
                res.append(i)
        return res

排序+双指针:

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        nums1.sort()
        nums2.sort()
        # 指针
        p1, p2 = 0, 0
        res = []
        while p1 < len(nums1) and p2 < len(nums2):
            if nums1[p1] == nums2[p2]:
                if res == [] or nums1[p1] != res[-1]:
                    res.append(nums1[p1])
                p1 += 1
                p2 += 1
            elif nums1[p1] < nums2[p2]:
                p1 += 1
            else:
                p2 += 1
        return res

用两个集合去重:

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        set1 = set(nums1)
        set2 = set(nums2)
        return self.set_intersection(set1, set2)

    def set_intersection(self, set1, set2):
        if len(set1) > len(set2):
            return self.set_intersection(set2, set1)
        return [x for x in set1 if x in set2]

12. 寻找两个正序数组的中位数

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        len1 = len(nums1)
        len2 = len(nums2)
        lens = len(nums1) + len(nums2)

        l , r = 0, 0
        p1, p2 = 0, 0
        for _ in range(lens//2 + 1):
            l = r
            if p1 < len(nums1) and (p2 >= len(nums2) or nums1[p1] < nums2[p2]):
                r = nums1[p1]
                p1 += 1
            else:
                r = nums2[p2]
                p2 += 1
        return (l+r)/2 if lens%2 == 0 else r

13. 二分查找

class Solution:
    def search(self , nums: List[int], target: int) -> int:
        # 首尾指针,依次通过mid进行对比
        l = 0
        r = len(nums)-1
        while l<=r:
            mid = (l+r)//2
            if nums[mid] < target:
                l = mid + 1
            elif nums[mid] > target:
                r = mid - 1
            else:
                return mid
        return -1

14. 旋转数组的最小数字(二分查找)

class Solution:
    def minNumberInRotateArray(self , rotateArray: List[int]) -> int:
        if len(rotateArray) == 0: return 0
        i, j = 0, len(rotateArray)-1
        # 不断缩小边界,找到最小值
        while i < j:
            m = (i+j)//2
            if rotateArray[m] > rotateArray[j]:
                i = m + 1
            elif rotateArray[m] < rotateArray[j]:
                j = m
            else:
                j -= 1
        return rotateArray[i]

15. 二维数组中的查找(二分查找)

二层循环(暴力搜索):

class Solution:
    def Find(self , target: int, array: List[List[int]]) -> bool:
        for i in range(len(array)):
            for j in range(len(array[0])):
                if array[i][j] == target:
                    return True
        return False

二分查找(分治思想):

class Solution:
    def Find(self , target: int, array: List[List[int]]) -> bool:
        if len(array) == 0 or len(array[0]) == 0: return False
        n = len(array)
        m = len(array[0])
        # 从左下角开始搜索
        i = n -1
        j = 0
        while i >= 0 and j < m:
            if array[i][j] > target:
                i -= 1
            elif array[i][j] < target:
                j += 1
            else:
                return True
        return False

16. 寻找峰值(二分)

暴力搜索:

class Solution:
    def findPeakElement(self , nums: List[int]) -> int:
        # 首尾特殊情况
        if len(nums) <= 1:
            return 0
        elif len(nums) == 2:
            return 0 if nums[0] > nums[1] else 1
        elif nums[0] >= nums[1]:
            return 0
        elif nums[len(nums)-1] > nums[len(nums)-2]:
            return len(nums)-1
        
        m = 1
        while m <= len(nums)-2:
            if nums[m-1] <= nums[m] and nums[m+1] <= nums[m]:
                return m
            m += 1
        return -1

二分查找(分治思想):

class Solution:
    def findPeakElement(self , nums: List[int]) -> int:
        l = 0
        r = len(nums) - 1
        while l < r:
            m = (l+r)//2
            # 不断限制区间,m大则缩小右边界,m小则缩小左边界
            if nums[m] > nums[m+1]:
                r = m
            else:
                l = m + 1
        # 当 l == r 时,即为一个峰
        return r

17. 数组中的逆序对

class Solution:
    def InversePairs(self , data: List[int]) -> int:
        res = 0
        for i in range(len(data)):
            for j in range(i+1, len(data)):
                if data[i] > data[j]:
                    res += 1
                    res %= 1000000007
        return res

归并排序(分治)

class Solution:
    def MergeSort(self, l: int, r: int, data: List[int], tmp: List[int]) -> int:
        if l >= r:
            return 0
        m = (l+r)//2
        res = self.MergeSort(l, m, data, tmp) + self.MergeSort(m + 1, r, data, tmp)
        res %= 1000000007

        i = l
        j = m + 1
        for n in range(l, r+1):
            tmp[n] = data[n]
        for n in range(l, r+1):
            if i == m + 1:
                data[n] = tmp[j]
                j += 1
            elif j == r + 1 or tmp[i] <= tmp[j]:
                data[n] = tmp[i]
                i += 1
            else:
                data[n] = tmp[j]
                j += 1
                # 统计逆序对
                res += m -i + 1
        return res%1000000007

    def InversePairs(self , data: List[int]) -> int:
        tmp = [0 for i in range(len(data))]
        return self.MergeSort(0, len(data)-1, data, tmp)

18. 数组的全排列(递归)

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        if len(nums) == 1: return [nums]
        res = []
        for i in range(len(nums)):
            tmp = nums[:i] + nums[i+1:]
            p = self.permute(tmp)
            for x in p:
                res.append([nums[i]]+x)
        return res

回溯(深度优先遍历+状态重置)

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        def backtrack(first = 0):
            # 所有数都填完了
            if first == len(nums):  
                res.append(nums[:])
            for i in range(first, len(nums)):
                # 动态维护数组
                nums[first], nums[i] = nums[i], nums[first]
                # 继续递归填下一个数
                backtrack(first + 1)
                # 撤销操作
                nums[first], nums[i] = nums[i], nums[first]
        backtrack()
        return res

19. 没有重复项数字的全排列

class Solution:
    # 递归
    def recursion(self, res: List[List[int]], num: List[int], index: int):
        # 分枝进入结尾,找到一种排列
        if index == len(num) - 1:
            res.append(num)
        else:
            # 遍历后续的元素
            for i in range(index, len(num)):
                # 交换
                num[i], num[index] = num[index], num[i]
                # 递归
                self.recursion(res, num, index + 1)
                # 回溯
                num[i], num[index] = num[index], num[i]

    def permute(self , num: List[int]) -> List[List[int]]:
        num.sort()
        res = list(list())
        self.recursion(res, num, 0)
        return res

20. 有重复项数字的全排列

class Solution:
    def recursion(self, res: List[List[int]], num: List[int], tmp: List[int], vis: List[int]):
        # 临时数组满了加入到结果集
        if len(tmp) == len(num):
            res.append(tmp.copy())
            return
        for i in range(len(num)):
            if vis[i] == 1:
                continue
            if i > 0 and num[i - 1] == num[i] and not vis[i - 1]:
                # 当前的元素num[i]与同一层的前一个元素num[i-1]相同num[i-1]已经用过了
                continue
            vis[i] = 1
            tmp.append(num[i])
            self.recursion(res, num, tmp, vis)
            vis[i] = 0
            tmp.pop()
    def permuteUnique(self , num: List[int]) -> List[List[int]]:
        num.sort()
        # 标记每个元素是否被使用过
        vis = [0]*len(num)
        res = list(list())
        tmp = list()
        self.recursion(res, num, tmp, vis)
        return res

21. 数组中出现次数超过一半的数字(哈希Map记录出现次数)

class Solution:
    def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
        map = dict()
        for i in range(len(numbers)):
            if numbers[i] in map:
                map[numbers[i]] += 1
            else:
                map[numbers[i]] = 1
            if map[numbers[i]] > len(numbers)//2:
                return numbers[i]
        return 0

22. 数组中只出现一次的两个数字(哈希Map记录出现次数)

class Solution:
    def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
        map = dict()
        res = []
        for i in range(len(array)):
            if array[i] in map:
                map[array[i]] += 1
            else:
                map[array[i]] = 1
        # 再次遍历数组,找到频率为1的两个数
        for i in range(len(array)):
            if map[array[i]] == 1:
                res.append(array[i])
        res.sort()
        return res

异或运算

class Solution:
    def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
        res = [0, 0]
        tmp = 0
        for i in range(len(array)):
            tmp ^= array[i]
        k = 1
        while k & tmp == 0:
            k <<= 1
        for i in range(len(array)):
            if k & array[i] == 0:
                res[0] ^= array[i]
            else:
                res[1] ^= array[i]
        res.sort()
        return res

23. 缺失的第一个正整数(哈希Map记录出现次数)

class Solution:
    def minNumberDisappeared(self , nums: List[int]) -> int:
        map = dict()
        for i in range(len(nums)):
            if nums[i] in map:
                map[nums[i]] += 1
            else:
                map[nums[i]] = 1
        res = 1
        while res in map:
            res += 1
        return res

猜你喜欢

转载自blog.csdn.net/qq_52057693/article/details/128787122