【刷题】数组类常见题(Python编写)

数组篇

1.二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        if not array:
            return False
        r1 = 0; r2 = len(array) - 1
        c1 = 0; c2 = len(array[0]) - 1
        
        while r1 <= r2 and c2 >= c1 :
            if target == array[r1][c2]:
                return True
            elif target > array[r1][c2]:
                r1 = r1 + 1
            else :
                c2 = c2 -1
        return False

带输入版本:

class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        if not array:
            return 'false'
        r1 = 0; r2 = len(array) - 1
        c1 = 0; c2 = len(array[0]) - 1
        
        while r1 <= r2 and c2 >= c1 :
            if target == array[r1][c2]:
                return 'true'
            elif target > array[r1][c2]:
                r1 = r1 + 1
            else :
                c2 = c2 -1
        return 'false'
    
while True:
    try:
        S=Solution()
        #字符串转为list
        L=list(eval(raw_input()))
        array=L[1]
        target=L[0]
        print(S.Find(target,array))
    except:
        break

6.旋转数组中的最小值

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

二分查找:

注意如果数组元素允许重复,会出现一个特殊的情况:nums[l] == nums[m] == nums[h],此时无法确定解在哪个区间,需要切换到顺序查找。例如对于数组 {1,1,1,0,1},l、m 和 h 指向的数都为 1,此时无法知道最小数字 0 在哪个区间。

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if len(rotateArray) == 0:
            return 0
         
        l = 0; h = len(rotateArray) - 1
        while l < h :
            m = l + (h - l)/2
            if rotateArray[m] == rotateArray[l] and rotateArray[m] == rotateArray[h]:
                return self.minNumber(rotateArray, l, h)
            if rotateArray[m] <= rotateArray[h]:
                h = m
            else:
                l = m + 1
        return rotateArray[l]
     
    def minNumber(self,rotateArray, l, h):
        for i in range(l,h):
            if (rotateArray[i] > rotateArray[i + 1]):
                return rotateArray[i + 1]
        return rotateArray[l]

11.调整数组使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

法一:lambda表达式

# 运行时间:24ms
# 占用内存:5852k
class Solution:
    def reOrderArray(self, array):
        # write code here
       return sorted(array, key=lambda c : c % 2, reverse = True)

法二:操作数组

class Solution:
    def reOrderArray(self, array):
        # write code here
        l = 0
        r = len(array) - 1
        while l <= r:
            if (array[l] % 2) == 0 :
                array.append(array[l])
                array.pop(l)
                r -= 1
            else:
                l += 1
        return array

法三:冒牌排序

class Solution:
    def reOrderArray(self, array):
        # write code here
        n = len(array)
        for i in range(n):
            for j in range(0, n-i-1):
                if self.isEven(array[j]) and not self.isEven(array[j + 1]):
                    self.swap(array, j, j+1)
        return array
    
    def swap(self,array, l, h):
        val = array[l]
        array[l] = array[h]
        array[h] = val
    
    def isEven(self,x):
        if x % 2 == 0 : 
            return True
        else:
            return False

法四:创建两个数组,一个保存奇数+一个保存偶数

class Solution:
    def reOrderArray(self, array):
        # write code here
        list1 = []
        list2 = []
        i = 0
        while i < len(array):
            if (array[i] % 2 == 0):
                list2.append(array[i])
            else:
                list1.append(array[i])
            i += 1
        return list1 + list2

19.顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        if matrix == []: 
            return False
        
        r1 = 0;r2 = len(matrix) - 1
        c1 = 0;c2 = len(matrix[0]) - 1
        result = []
        
        while r1 <= r2 and c1 <= c2:
            for i in range(c1, c2 + 1):
                result.append(matrix[r1][i])
            for i in range(r1 + 1, r2 + 1):
                result.append(matrix[i][c2])
            if r1 != r2:
                for i in range(c2 - 1, c1 - 1, -1):
                    result.append(matrix[r2][i])
            if c1 != c2:
                for i in range(r2 - 1, r1, -1):
                    result.append(matrix[i][c1])
            r1 += 1; r2 -= 1; c1 += 1; c2 -= 1
            
        return result

28.数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

法一:排序后找中位数

法二:统计次数后,消减

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        if len(numbers) == 0:
            return 0
        
        count = 1
        val = numbers[0]
        for i in range(1,len(numbers)):
            count = (count - 1 if numbers[i] != val else count + 1)  # 统计出现次数
            if count == 0:
                val = numbers[i]
                count = 1
                
        count = 0
        for i in numbers:
            if i == val:
                count += 1
                
        return (val if count > len(numbers)//2 else 0)  # 判断是否超过一半

30.连续子数组最大和

给一个数组,返回它的最大连续子序列的和(子向量的长度至少是1)

例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。

动态规划

# -*- coding:utf-8 -*-
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        if len(array) == 0:
            return 0
        
        maxV = array[0]
        tmp = array[0]
        for i in range(1,len(array)):
            if (array[i] + tmp) > array[i]:
                tmp = array[i] + tmp
            else:
                tmp = array[i]
            if tmp > maxV:
                maxV = tmp
                
        return maxV

利用python自带的max函数,可以更简便:

class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        if len(array) == 0:
            return 0
        
        maxV = array[0]
        tmp = array[0]
        for i in range(1,len(array)):
            tmp = max(array[i] + tmp, array[i])
            maxV = max(tmp,maxV)
        return maxV

32.把数组排出最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

# 很厉害的代码
class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        if not numbers:
            return ""
        lmb = lambda n1, n2:int(str(n1)+str(n2))-int(str(n2)+str(n1))
        array = sorted(numbers, cmp=lmb)
        return ''.join([str(i) for i in array])

35.数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

法1:归并排序,时间复杂度O(nlogn)

我的写法:相当于手写了一个归并排序!

count = 0
class Solution:
    def InversePairs(self, data):
        # write code here
        global count
        if data == []:
            return 0
        self.mergersort(data)
        return count % 1000000007
    
    def mergersort(self,data):
        n = len(data)
        if n < 2:
            return   
        m = n // 2
        s1 = data[:m]
        s2 = data[m:]
        self.mergersort(s1)
        self.mergersort(s2)
        self.merger(s1, s2, data)
        
    def merger(self,s1,s2,s):
        i = j = 0
        global count
        while i < len(s1) or j < len(s2):
            if i > len(s1) - 1:
                s[i+j] = s2[j]; j += 1
            elif j > len(s2) - 1:
                s[i+j] = s1[i]; i += 1
            elif s1[i] < s2[j]:
                s[i+j] = s1[i]; i += 1
            else:
                s[i+j] = s2[j]; j += 1
                count += len(s1) - i
        return s

别人的写法:

count = 0
class Solution:
    def InversePairs(self, data):
        global count
        def MergeSort(lists):
            global count
            if len(lists) <= 1:
                return lists
            num = int( len(lists)/2 )
            left = MergeSort(lists[:num])
            right = MergeSort(lists[num:])
            r, l=0, 0
            result=[]
            while l<len(left) and r<len(right):
                if left[l] < right[r]:
                    result.append(left[l])
                    l += 1
                else:
                    result.append(right[r])
                    r += 1
                    count += len(left)-l
            result += right[r:]
            result += left[l:]
            return result
        MergeSort(data)
        return count%1000000007

法二:暴力法

直接暴力法,双指针,判断当前指针的数是否大于第二个指针的数字。

# 运行超时不通过
class Solution:
    def InversePairs(self, data):
        # write code here
        length = len(data)
        count = 0
        for i in range(length-1):
            for j in range(i+1, length):
                if data[i] > data[j]:
                    count += 1
        return count%1000000007

法三:

将原数组排序,然后从小到大遍历排序数组,求这个数在原数组中的index,这个index就代表有多少个数字在该数的前面。

# 运行超时不通过
class Solution:
    def InversePairs(self, data):
        # write code here
        data2 = sorted(data)  # 相当于自动归并排序
        length = len(data)
        count = 0
        for num in data2:
            count += data.index(num)
            data.remove(num)
        return count%1000000007

37.数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数。

Input:
nums = 1, 2, 3, 3, 3, 3, 4, 6
K = 3
Output:
4

最简单的解法:

class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        return data.count(k)

法二:顺序判断(适合数据量不大)

class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        count = len(data)
        i = 0
        for j in range(count):
            if data[j] == k:
                i += 1
        return i

法三:

从两头分别找第一个和最后一个k的位置,计算位置差

class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        if len(data) == 0:
            return 0
        i = 0;
        j = len(data) - 1
        while i < j and data[i] != data[j]:
            if data[i] < k:
                i += 1
            if data[j] > k:
                j -= 1
        if data[i] != k:
            return 0
        return j - i + 1

40.数组中自出现过一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

思路:

1.异或全部数组,得diff
2.找到diff最右侧第一个为1的位置,记为n位 ,diff &= -diff
3.利用n位为1或为0将原数组分为两组
4.对每组进行异或,可得到每组只出现一次的数字

class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
        
        res = [0,0]
        diff = 0
        for i in array:
            diff ^= i
            
        diff &= -diff      
        for i in array:
            if (i & diff) == 0:
                res[0] ^= i
            else:
                res[1] ^= i
        return res

50.数组中的重复数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        if numbers is None:
            return False

        for i in range(len(numbers)):
            while numbers[i] != i:
                if numbers[i] == numbers[numbers[i]]:
                    duplication[0] = numbers[i]
                    return True
                self.swap(numbers, i, numbers[i])
        return False

    def swap(self, nums, i, j):
        item = nums[i]
        nums[i] = nums[j]
        nums[j] = item

51.构建乘积数组

给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)

解法

分两段乘,先从左往右乘,在从右往左乘

class Solution:
    def multiply(self, A):
        # write code here
        if A is None:
            return None
        
        B = [1] * len(A)
        mul = 1
        for i in range(len(A)):
            B[i] = mul
            mul *= A[i]
            
        mul = 1
        for i in range(len(A)- 1,-1,-1):
            B[i] *= mul
            mul *= A[i]
        
        return B
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值