珍宝鸭的力扣练习(10):数组特殊方法合集

方法1:二分法

**二分法:
mid=(left+right)/2
left=mid+1
right=mid

例题1:不在排序数组内的数字

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例 1:
输入: [0,1,3]
输出: 2
示例 2:
输入: [0,1,2,3,4,5,6,7,9]
输出: 8

不多废话直接看代码:

class Solution(object):
    def missingNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        def helper(b1,b2):#p为下表处理
            if b1==b2:
                if b1==nums[b1]:
                    return b1+1
                else:
                    return b1
            # 计算新的中位下标=======
            if (b1+b2)%2==1:
               mid=int((b1+b2-1)/2)
            else:
                mid=int((b1+b2)/2-1)
            if mid==nums[mid]:
                return helper(mid+1,b2)
            else:
                return helper(b1,mid)

        return helper(0,len(nums)-1)

例题2:target开始与结束位置

在这里插入图片描述

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        n = len(nums); L = 0; R = n
        while L < R:
            mid = int(L + (R-L)/2)
            if nums[mid] == target:
                start = mid - 1; end = mid + 1
                while start >= 0 and nums[start] == target: start-=1
                while end < n and nums[end] == target: end+=1
                return [start+1, end-1]
            elif nums[mid] < target: L = mid + 1
            else: R = mid
        return [-1, -1]


例题3:旋转数组的最小值

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
在这里插入图片描述
们考虑数组中的最后一个元素 x:在最小值右侧的元素,它们的值一定都小于等于 x;而在最小值左侧的元素,它们的值一定都大于等于 x。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。

class Solution(object):
    def minArray(self, numbers):
        """
        :type numbers: List[int]
        :rtype: int
        """
        if len(numbers)==1: return numbers[0]
        i,j=0,len(numbers)-1
        while i<j:
            mid=(i+j)//2
            #如果mid在最小值左侧
            if numbers[mid]>numbers[j]:
                i=mid+1
            #如果mid在最小值左侧
            elif numbers[mid]<numbers[j]:
                j=mid
            else:
                j-=1
        return numbers[i]

例题4:排序数组中target的个数

统计一个数字在排序数组中出现的次数。
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        count=0
        def helper(left,right):
            if left>=right: return left,right
            mid=(left+right)//2
            if target<nums[mid]:
                return helper(left,mid)
            elif target>nums[mid]:
                return helper(mid+1, right)
            else:
                return left,right
        l,r= helper(0,len(nums)-1)
        if l==r:
            return 1 if nums[r]==target else 0
        count=0
        for i in range(l,r+1):
            if nums[i]==target:
                count+=1
        return count

s=Solution()
print(s.search([5,7,7,8,8,10],6))

方法2:摩尔投票法

哈希表统计法: 遍历数组 nums ,用 HashMap 统计各数字的数量,即可找出 众数 。此方法时间和空间复杂度均为 O(N)O(N) 。
数组排序法: 将数组 nums 排序,数组中点的元素 一定为众数。
摩尔投票法: 核心理念为 票数正负抵消 。此方法时间和空间复杂度分别为 O(N)O(N) 和 O(1)O(1) ,为本题的最佳解法。

例题1:不在数组内的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

摩尔投票法:
设输入数组 nums 的众数为 x ,数组长度为 n 。

推论一: 若记 众数 的票数为 +1 ,非众数 的票数为 −1 ,则一定有所有数字的 票数和 >0(题目条件:总存在一个多数元素) 。

推论二: 若数组的前 a个数字的 票数和 = 0,则 数组剩余(n−a) 个数字的票数和一定仍 >0 ,即后 (n−a) 个数字的 众数仍为 x (题目条件:总存在一个多数元素)

根据以上推论,假设数组首个元素 n_1。
当发生 票数和=0 时,剩余数组的众数一定不变 ,这是由于:

当 n_1=x: 抵消的所有数字,有一半是众数 x 。
当 n_1≠x : 抵消的所有数字,少于或等于一半是众数 x 。

利用此特性,每轮假设发生 票数和 = 0=0 都可以 缩小剩余数组区间 。当遍历完成时,最后一轮假设的数字即为众数。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        votes = 0
        for num in nums:
            if votes == 0: x = num
            if num == x:
            	votes += 1  
            else:
          	  votes += 1  
        return x

方法3:滑动窗口法

滑动窗口可以看成数组中框起来的一个部分。在一些数组类题目中,我们可以用滑动窗口来观察可能的候选结果。当滑动窗口从数组的左边滑到了右边,我们就可以从所有的候选结果中找到最优的结果。

例题1:和为target的连续序列

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
输入:target = 9
输出:[[2,3,4],[4,5]]

题解:当窗口的和小于 target 的时候,窗口的和需要增加,所以要扩大窗口,窗口的右边界向右移动。
当窗口的和大于 target 的时候,窗口的和需要减少,所以要缩小窗口,窗口的左边界向右移动。
当窗口的和恰好等于 target 的时候,我们需要记录此时的结果。设此时的窗口为 [i, j),那么我们已经找到了一个 i 开头的序列,也是唯一一个 i 开头的序列,接下来需要找 i+1开头的序列,所以窗口的左边界要向右移动。

class Solution(object):
    def findContinuousSequence(self, target):
        """
        :type target: int
        :rtype: List[List[int]]
        """
        result=[]
        stack=[1]
        n=1
        while stack:
            if sum(stack)<target:
                n+=1
                stack.append(n)
            elif sum(stack)>target:
                stack.pop(0)
            else:
                if len(stack)>1:
                    result.append(stack[:])
                n += 1
                stack.append(n)
        return result

典型例题:数组扁平化

数组的扁平化,就是将一个嵌套多层的数组 array (嵌套可以是任何层数)转换为只有一层的数组。

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


 let arr = [1, [2, [3, 4]]];
 
 function flattern(arr) {
        let result = [];
        for(let i = 0; i < arr.length; i++) {
            if(Array.isArray(arr[i])) {
                flattern(arr[i])
            } else {
                result.push(arr[i])
            }
        }
        return result;
    }
console.log(flattern(arr));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值