python数组经典题目(二分查找、交换、桶求最大差、只出现1次的数、众数问题、前缀和应用)

一、数组查找(用二分法:一般求局部极小值、数组部分有序)
例 一个给定的不包含相同元素的整数数组,求它的一个局部最小值(局部极小值的定义是一个值比左右相邻的(如果存在)都小的值)

#复杂度O(logn)
def findmix(A):
    length = len(A)
    if length < 2:
        return 0
    left = 0
    right = length -1
    while left <= right:
        if left == right:
            return A[left]
        mid = (left + right) // 2
        if A[mid] < A[mid + 1]:
            right = mid
        else:
            left = mid + 1

leetcode153、154类型同,33、81类型同,154、81有重复,重点去掉mid和right部分末尾重复内容,使其能判断是否单调,可对照看
leetcode153. Find Minimum in Rotated Sorted Array

class Solution:
    def findMin(self, nums):
        left = 0
        right = len(nums)-1
        while left <= right:
            if left == right:
                return nums[left]
            mid = (left + right) // 2
            if nums[mid] > nums[right]:
                left = mid + 1
            else:
                right = mid

leetcode154. Find Minimum in Rotated Sorted Array II

class Solution:
    def findMin(self, nums):
        left = 0
        right = len(nums)-1
        while left <= right:
            if left == right:
                return nums[left]
            mid = (left + right) // 2
            while mid < right and nums[mid] == nums[right]:
                right -= 1
            if nums[mid] <= nums[right]:
                right = mid
            else:
                left = mid + 1

leetcode33. Search in Rotated Sorted Array

#O(logn)重点:先判断mid对应值是否等于target,然后通过判断mid和right对应值的大小判断
#哪一段是单调的,进而分别判断这个数是否在这一段中,进行取半操作
class Solution:
    def search(self, nums, target):
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            if nums[mid] < nums[right]:
                if nums[mid] < target <= nums[right]:
                    left = mid + 1
                else:
                    right = mid - 1
            else:
                if nums[left] <= target < nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
        return -1

leetcode81. Search in Rotated Sorted Array II

class Solution:
    def search(self, nums, target):
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return True
            while mid < right and nums[mid] == nums[right]:    #这一步是关键
                right -= 1
            if nums[mid] <= nums[right]:
                if nums[mid] < target <= nums[right]:
                    left = mid + 1
                else:
                    right = mid - 1
            else:
                if nums[left] <= target < nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
        return False

二、交换
以下几道题均用的是41思路,时间复杂度O(n)
leetcode41. First Missing Positive

#分三种情况,a[i] == i+1时i+=1,否则将不可能有正确位置的元素去除(包括,<1的,数值超过
#最大长度的,或是其正确位置已经有与其一样大的数占用的),剩下的是有正确位置的,所以
#将其与正确位置元素进行交换
class Solution:
    def firstMissingPositive(self, nums):
        n = len(nums)
        i = 0
        while i < n:
            if i + 1 == nums[i]:
                i += 1
            elif nums[i] < 1 or nums[i] > n or nums[i] == nums[nums[i] - 1]:
                nums[i] = nums[n - 1]
                n -= 1
            else:
                pos = nums[i]
                nums[i] = nums[pos - 1]
                nums[pos - 1] = pos
        return n+1

leetcode268. Missing Number

class Solution:
    def missingNumber(self, nums):
        n = len(nums)
        i = 0
        while i < n:
            if nums[i] == i:
                i += 1
            elif nums[i] > n - 1:
                nums[i] = nums[n-1]
                n -= 1
            else:
                pos = nums[i]
                nums[i] = nums[pos]
                nums[pos] = pos
        return n

另一种方式,很简单

class Solution:
    def missingNumber(self, nums):
        n = len(nums)
        for i in range(n+1):
            if i not in nums:
                return i

leetcode287. Find the Duplicate Number

class Solution:
    def findDuplicate(self, nums):
        n = len(nums)
        i = 0
        while i < n:
            if nums[i] == i + 1:
                i += 1
            elif nums[nums[i] - 1] == nums[i]:
                return nums[i]
            else:
                pos = nums[i]
                nums[i] = nums[pos - 1]
                nums[pos - 1] = pos

三、元素最大间距离
leetcode164. Maximum Gap

**#  时间复杂度O(n)**
class Solution:
    def maximumGap(self, nums):
        n = len(nums)
        if n < 2:
            return 0
        x = max(nums)
        y = min(nums)
        if x == y:
            return 0
        buckets = [[] for i in range(n+1)]     #将n个数放n+1个桶里
        for i in nums:
            pos = (i-y)*(n+1)//(x-y)
            if pos == (n+1):   #注:最大的数要放最后一个桶里,因为最后一个桶是闭的
                buckets[pos-1].append(i)
            else:
                buckets[pos].append(i)
        max_gap = 0
        for i in range(n+1):
            if buckets[i] == []:
                j = i + 1
                k = i - 1
                while buckets[j] == []:
                    j += 1
                while buckets[k] == []:
                    k -= 1
                gap = min(buckets[j])-max(buckets[k])
                if gap > max_gap:
                    max_gap = gap
        return max_gap

四、只出现1次的数
重点:想消去出现两次的数(136.260),做异或;对于出现次数不一致时(137),每一位对应相加%3;这类题也可以用字典,时间空间用的差不多
leetcode136. Single Number

class Solution:
    def singleNumber(self, nums):
        tmp = 0
        for i in nums:  #所有数做异或
            tmp ^= i
        return tmp

leetcode260. Single Number III

class Solution:
    def singleNumber(self, nums):
        tmp = 0
        for i in nums:  #所有数做异或
            tmp ^= i
        print(tmp)
        pos = 1
        while pos&tmp == 0:  #判断出x与y两数不相等的位置pos
            pos = pos<<1
        print(pos)
        x=y=0
        for i in nums:
            if i & pos == pos: #判断数是否与pos位相等,就与pos相比
                x ^= i
            else:
                y ^= i
        return x,y

leetcode137. Single Number II

class Solution:
    def singleNumber(self, nums):
        res = 0
        for i in range(31, -1, -1):
            count = 0
            for num in nums:
                count += (num >> i) & 1
            rem = count % 3
            if rem != 0:
                if i == 31:
                    res -= 1 << 31
                else:
                    res += 1<

1-100,缺少了两个数,求这两个数?

#这道题与260类似:将这个缺了两个数的数组arr的所有数与1-100放一块,其实就是260,其他数
#出现两次,就缺的这两个数出现一次

五、众数问题
核心:每次扔掉两个或多个不同的数,剩下的就是想要的
leetcode169. Majority Element

class Solution:
    def majorityElement(self, nums):
        count = 0
        tmp = 0
        for num in nums:
            if count == 0:
                tmp = num
            if num == tmp:
                count += 1
            else:
                if count != 0:
                    count -= 1
                else:
                    tmp = num
        return tmp

leetcode229. Majority Element II

class Solution:
    def majorityElement(self, nums):
        count1 = count2 = 0
        tmp1 = tmp2 = 1.1
        for num in nums:
            if num == tmp1:
                count1 += 1
            elif num == tmp2:
                count2 += 1
            else:
                if count1 == 0:
                    tmp1 = num
                    count1 = 1
                elif count2 == 0:
                    tmp2 = num
                    count2 = 1
                else:
                    count1 -= 1
                    count2 -= 1
        res = []
        if nums.count(tmp1) > len(nums)//3:
            res.append(tmp1)
        if nums.count(tmp2) > len(nums) // 3:
            res.append(tmp2)
        return res

六、前缀和的应用
给定浮点数组a,求一个数组b, b[i] = a[0] * a[1] *…*a[i – 1] * a[i + 1] * …*a[n – 1],不能使用除法,不允许再开数组

class Solution:
    def mutiplies(self, a):
        n = len(a)
        b = [1]*n
        for i in range(n):
            for m in range(n-1,i,-1):
                b[i] *= a[m]
            for m in range(0,i):
                b[i] *= a[m]
        return b

求数组中连续一段和,绝对值最小?

class Solution:
    def majorityElement(self, a):
        n = len(a)
        sum = [0] * n      
        for i in range(n):    #创建前缀和sum
            for j in range(i+1):
                sum[i] += a[j]
        sum.sort()           #将sum排序
        minsum = float('inf')
        for i in range(n-1):    #相邻做差去最小
            dif = sum[i+1]-sum[i]
            if dif < minsum:
                minsum = dif
        return minsum

把一个数组从中间p位置分开,使得a[0] + …+ a[p – 1]与a[p] + a[p + 1] + …+ a[n – 1]差值最小?

class Solution:
    def majorityElement(self, a):
        n = len(a)
        sum = [0] * n
        for i in range(n):    #创建前缀和sum
            for j in range(i+1):
                sum[i] += a[j]
        minsum = float('inf')
        print(sum)
        for i in range(1,n-1):    #相邻做差去最小
            dif = sum[n-1]-2*sum[i-1]
            if dif < minsum:
                minsum = dif
        return minsum

你可能感兴趣的:(python数组经典题目(二分查找、交换、桶求最大差、只出现1次的数、众数问题、前缀和应用))