剑指offer数组练习汇总

这里总结了剑指offer的数组部分练习,主要是牛客网的题目。

我的整体感觉难度适中,主要是其中都有一些既定的套路或者规律,另外如果我还会参考一些网友的作答以便给大家完整的思路。

注:
这里的题号是牛客网的题号。

NO.1

在这里插入图片描述
在这里插入图片描述
有一个特点就是左下角和右上角的数据,如果target大于或者小于都只有一个方向可以进行移动,比如左下角只有右边(小于target),上边(大于target)。

由此利用这个特点进行遍历。

时间复杂度最好是O(1),最坏是O(2n)

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        x_len, y_len = len(array) - 1, len(array[0]) - 1
        x, y = x_len, 0
        while(x > -1 and y <= y_len):
            if target == array[x][y]:
                return True
            elif target > array[x][y]:
                y += 1
            else:
                x -= 1
        return False

在这里插入图片描述
方法二:
标准的查找思路,每一个数组进行二分查找,这其实是我的解题思路,一开始就想到的是这样的方法。

这里大家还是对二分有一个熟练的掌握比较好,另外使用循环比递归要好。

class Solution:
    def Find(self, target, array):
        for arr in array:
            flag = search(arr, target)
            if flag:
                return True
        return False
    
def search(arr, target):
        start, end = 0, len(arr) - 1
        while(start <= end): 
            mid = int((start + end) / 2)
            print(start, end, mid)
            if target > arr[mid]:
                start = mid + 1
            elif target < arr[mid]:
                end = mid - 1
            else:
                return True
        return False

在这里插入图片描述

NO.13

在这里插入图片描述
思路一:开辟新空间
利用python特有的数据结构
双向队列,说实话这个deque还真的是第一次用:

from collections import deque
class Solution:
    def reOrderArray(self, array):
        res = deque()
        for i in range(len(array)):
            if array[i] % 2 == 0:
                res.append(array[i])
            if array[len(array) - i - 1] % 2 == 1:
                res.appendleft(array[len(array) - i - 1])
        return res

在这里插入图片描述
思路二:利用稳定的排序算法思路
冒泡排序,只要遇到偶奇相邻就进行交换

class Solution:
    def reOrderArray(self, array):
        for i in range(len(array)):
            for j in range((len(array) - 1), i, -1):
                if(array[j-1]%2==0 and array[j]%2==1):
                    tmp = array[j-1]
                    array[j-1] = array[j]
                    array[j] = tmp
        return array

在这里插入图片描述

或者插入排序,
主要思路就是有一个对于最后一个奇数的位置标的,找到一个奇数需要将pos和i中间的数后移一位

class Solution:
    def reOrderArray(self, array):
        pos = 0
        for i in range(len(array)):
            if array[i] % 2 == 1:
                tmp = array[i]
                for m in range(i, pos, -1):
                    array[m] = array[m-1]
                array[pos] = tmp
                pos += 1
        return array

在这里插入图片描述

NO.19

在这里插入图片描述
我参考了牛客网上的华科平凡的答案,确实简洁高级。
学习了。

class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        matrixx = matrix[:]
        res = []
        while matrixx:
            res += matrixx.pop(0)
            if matrixx and matrixx[0]:
                for row in matrixx:
                    res.append(row.pop())
            if matrixx:
                res += matrixx.pop()[::-1]
            if matrixx and matrixx[0]:
                for row in matrixx[::-1]:
                    res.append(row.pop(0))
        return res

在这里插入图片描述

NO.28

在这里插入图片描述
这是比较直接的想法,我觉得复杂度也比用快排的效果更好。

class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        halfLen = len(numbers) // 2
        dictt = {}
        res = 0
        for i in numbers:
            if i in dictt.keys():
                dictt[i] += 1
            else:
                dictt[i] = 1
            if dictt[i] > halfLen:
                    return i
        return res

在这里插入图片描述
但是python有一些先天很方便的数据结构和封装,这里我们使用counter

import collections
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        halfLen = len(numbers) // 2
        counterr = collections.Counter(numbers)
        for k, v in counterr.items():
            if v > halfLen:
                return k
        return 0

在这里插入图片描述
但是用了快排似乎显得更高级:

class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        halfLen = len(numbers) // 2
        numberss = sorted(numbers)
        mid = numberss[halfLen]
        counter = 0
        for i in numberss:
            if i == mid:
                counter += 1
        if counter > halfLen:
            return mid
        return 0

python有sort我就不自己写排序了。

在这里插入图片描述

NO.29

在这里插入图片描述

class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        tinputt = sorted(tinput)
        if k > len(tinput):
            return []
        return tinputt[:k]

这道题只满足于用python这么解是没有意义的,很明显TopN问题,我会毫不犹豫的想到小根堆。

import heapq
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        heapq.heapify(tinput)
        if k > len(tinput):
            return []
        res = []
        for i in range(k):
            res.append(heapq.heappop(tinput))
        return res

在这里插入图片描述

NO.30

在这里插入图片描述
dp动态规划
dp[i]表示以第i个字符结尾的字符子串的最大子串和
dp[0] = array[0]
dp[i] = max(dp[i-1] + array[i], array[i])

class Solution:
    def FindGreatestSumOfSubArray(self, array):
        res = array[0]
        max_tmp = array[0]
        for i in range(1, len(array)):
            max_tmp = max(max_tmp+array[i], array[i])
            res = max(res, max_tmp)
        return res

在这里插入图片描述

class Solution:
    def FindGreatestSumOfSubArray(self, array):
        dp = [0 for i in range(len(array))]
        dp[0] = array[0]
        for i in range(1, len(array)):
            dp[i] = max(dp[i-1] + array[i], array[i])
        return max(dp)

在这里插入图片描述

NO.32

在这里插入图片描述

class Solution:
    def PrintMinNumber(self, numbers):
        cmp_rule = lambda x1, x2: int(''.join([str(x1), str(x2)])) - int(''.join([str(x2), str(x1)]))
        res = sorted(numbers, cmp=cmp_rule)
        return ''.join([str(i) for i in res])

在这里插入图片描述

如果使用原生的方法的话就是一个快排就可以了,不过重新定义cmp的规则

NO.35

在这里插入图片描述

class Solution:
    def __init__(self):
        self.counterr = 0
    def mergesort(self, seq):
        if len(seq) <= 1:
            return seq
        mid = len(seq) // 2
        left = self.mergesort(seq[:mid])
        right = self.mergesort(seq[mid:])
        return self.merge(left, right)
    def merge(self, left, right):
        result = []
        i, j = 0, 0
        while i<len(left) and j<len(right):
            if left[i] <= right[j]:
                result.append(left[i])
                i += 1
            else:
                self.counterr += len(left)-i
                result.append(right[j])
                j += 1
        result += left[i:]
        result += right[j:]
        return result
    def InversePairs(self, data):
        res = self.mergesort(data)
        return self.counterr%1000000007

在这里插入图片描述

NO.37

在这里插入图片描述

class Solution:
    def Counter(self, nums, pos, targetNum):
        left, right = pos, pos+1
        if len(nums) == 1:
            return 1
        while((left > -1) and nums[left] == targetNum):
            left -= 1
        while((right < len(nums)) and nums[right] == targetNum):
            right += 1
        return (right-left-1)
    def GetNumberOfK(self, data, k):
        left, right = 0, len(data) - 1
        while left <= right:
            mid = (left + right) // 2
            if data[mid] == k:
                return self.Counter(data, mid, k)
            elif data[mid] < k:
                left = mid + 1
            else:
                right = mid - 1
        return 0

第一感觉就是二分

在这里插入图片描述
但是我一看别人的代码,我疯了

class Solution:
    def GetNumberOfK(self, data, k):
        return data.count(k)

在这里插入图片描述

NO.40

在这里插入图片描述
最开始的想法是用一个字典来存储出现的次数,不过这得有两次遍历 是不是有更好的方法

class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        counter = {}
        for i in array:
            if i in counter:
                counter[i] -= 1
            else:
                counter[i] = 1
        return [i for i in counter.keys() if counter[i]==1]

在这里插入图片描述
空间复杂度O(1)的方法,使用bitmap,这里我倒是没有实现。

NO.42

在这里插入图片描述
这里我看到了一个非常漂亮的证明,感谢网友,我截图如下:

在这里插入图片描述
好的,那么就简单了:

class Solution:
    def FindNumbersWithSum(self, array, tsum):
        left, right = 0, len(array)-1
        res = []
        while(left < right):
            if array[left] + array[right] < tsum:
                left += 1
            elif array[left] + array[right] > tsum:
                right -= 1
            else:
                res.append(array[left])
                res.append(array[right])
                return res
        return res

在这里插入图片描述

NO.50

在这里插入图片描述
首先使用python封装好的词袋

import collections
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        counter = collections.Counter(numbers)
        for k, v in counter.items():
            if v > 1:
                duplication[0] = k
                return True
        return False

在这里插入图片描述
不过我还想一个通解,使用bitmap来进行记录。

import collections
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        lenth = len(numbers)
        bitmap = [0 for _ in range(lenth)]
        for i in range(lenth):
            if bitmap[numbers[i]]:
                duplication[0] = numbers[i]
                return True
            bitmap[numbers[i]] = 1
        return False

在这里插入图片描述

NO.51

在这里插入图片描述
这道题我看了好几遍竟然没有看懂,然后查看了解析,然后…然后就觉得似乎不是很难,但是再看题目还是不懂。
好吧,这里我把一个我认为讲的比较清楚地方法放在这里:

在这里插入图片描述

class Solution:
    def multiply(self, A):
        length = len(A)
        B = [1 for _ in range(length)]
        for i in range(1, length):
            B[i] = B[i-1] * A[i-1]
        tmp = 1
        for i in range(length-2, -1, -1):
            tmp *= A[i+1]
            B[i] *= tmp
        return B

在这里插入图片描述

NO.64

在这里插入图片描述

class Solution:
    def findMax(self, num, left, right):
        max_tmp = num[left]
        pos_tmp = left
        for i in range(left + 1, right+1):
            if max_tmp <= num[i]:
                max_tmp = num[i]
                pos_tmp = i
        return [max_tmp, pos_tmp]
    def maxInWindows(self, num, size):
        if size <= 0:
            return []
        left, right = 0, size - 1
        max_v = -1
        pos = -1
        res = []
        while right < len(num):
            max_v, pos = self.findMax(num, left, right)
            res.append(max_v)
            while (left < pos) and left < len(num)-size:
                left += 1
                right += 1
                if max_v <= num[right]:
                    pos = right
                    max_v = num[right]
                res.append(max_v)
            left += 1
            right += 1
        return res

在这里插入图片描述
然后看到了一个非常简洁的写法,觉得自己受到了羞辱:

class Solution:
    def maxInWindows(self, num, size):
        if size <= 0:
            return []
        res = []
        for i in xrange(0, len(num) - size + 1):
            res.append(max(num[i:i+size]))
        return res

在这里插入图片描述

NO.66

在这里插入图片描述
回溯法

class Solution:
    def __init__(self):
        self.count = 0

    def movingCount(self, threshold, rows, cols):
        arr = [[1 for _ in range(cols)] for _ in range(rows)]
        self.findway(arr, 0, 0, threshold)
        return self.count

    def findway(self, arr, i, j, k):
        if i < 0 or j < 0 or i >=len(arr) or j >= len(arr[0]):
            return
        tmpj = list(map(int, list(str(j))))
        tmpi = list(map(int, list(str(i))))
        if sum(tmpi) + sum(tmpj) > k or arr[i][j] != 1:
            return 
        arr[i][j] = 0
        self.count += 1
        self.findway(arr, i+1, j, k)
        self.findway(arr, i-1, j, k)
        self.findway(arr, i, j+1, k)
        self.findway(arr, i, j-1, k)

在这里插入图片描述

欢迎指正
大家共勉~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值