这里总结了剑指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)
欢迎指正
大家共勉~~