本篇博客介绍算法部分,涉及的算法有排序、回溯、动态规划、斐波那契数列、查找、位运算、全排列,还涉及数学知识、规律总结和扩展思维题目。
六、排序篇(2道题)
涉及内容:数组中的逆序对 (归并排序)
最小的K个数(快速排序等)
42.最小的K个数
题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路:按照各种排序算法,找到排序结果的前K个数。
代码:
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
#快速排序
#还有其它的排序方法,详见
#https://www.nowcoder.com/questionTerminal/6a296eb82cf844ca8539b57c23e6e9bf?f=discussion
def quick_sort(lst):
if not lst:
return []
pivot = lst[0]
left = quick_sort([x for x in lst[1: ] if x < pivot])
right = quick_sort([x for x in lst[1: ] if x >= pivot])
return left + [pivot] + right
if tinput == [] or k > len(tinput):
return []
tinput = quick_sort(tinput)
return tinput[: k]
43. 数组中的逆序对
题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出, 即输出P%1000000007。
思路:逆序对的个数等于完成由小到大排序数字时,数字两两之间交换的次数。
代码:
# -*- coding:utf-8 -*-
def MergeElem(data, start, mid, end, temp): # data[start...mid], data[mid+1...end]
cnt = 0
i = start
j = mid + 1
k = start
while i <= mid and j <= end:
if data[j] < data[i]: # data[start...i...mid] data[mid+1...j...end]
temp[k] = data[j]
cnt += j - k
j += 1
k += 1
else:
temp[k] = data[i]
i += 1
k += 1
while i <= mid:
temp[k] = data[i]
i += 1
k += 1
while j <= end:
temp[k] = data[j]
j += 1
k += 1
data[start:end+1] = temp[start:end+1]
return cnt
def InverseCore(data, start, end, temp):
cnt = 0
if start < end:
mid = (start + end) // 2
cnt += InverseCore(data, start, mid, temp)
cnt += InverseCore(data, mid+1, end, temp)
cnt += MergeElem(data, start, mid, end, temp)
return cnt
class Solution:
#归并排序
def InversePairs(self, data):
# write code here
temp = data[:]
count = InverseCore(data, 0, len(data)-1, temp)
return count%1000000007
七、回溯法(2道题)
涉及内容:矩阵中的路径
机器人的运动范围
44、矩阵中的路径
题目描述:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
思路:从任意结点开始,任选该结点的某一个方向,判断结点在某一方向的值是否等于路径中的数值。确定每一步都是正确的情况下,再考虑下一步,这也和“广度优先遍历”是类似的。
代码:
# -*- coding:utf-8 -*-
def BFS(matrix, row, col, path, visited):
if row < 0 or row >= len(matrix) or col < 0 or col >= len(matrix[0]) or visited[row][col]:
return False
if path[0] == matrix[row][col]:
if len(path) == 1:
return True
visited[row][col] = 1
if BFS(matrix, row+1, col, path[1:], visited) or \
BFS(matrix, row-1, col, path[1:], visited) or \
BFS(matrix, row, col-1, path[1:], visited) or \
BFS(matrix, row, col+1, path[1:], visited):
return True
return False
else:
return False
class Solution:
def hasPath(self, matrix, rows, cols, path):
# write code here
array = list(matrix)
array = [array[i*cols:(i+1)*cols] for i in range(rows)]
for i in range(rows):
for j in range(cols):
visited = [[0] * len(array[0]) for _ in range(len(array))]
if BFS(array, i, j, list(path), visited):
return True
return False
45. 机器人的运动范围
题目描述:地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路:和第34题类似,也是要判断每一步是否满足格子的横纵坐标和的不等式约束。
代码:
# -*- coding:utf-8 -*-
def getN(i, j):
res = 0
while i:
res += (i % 10)
i //= 10
while j:
res += (j % 10)
j //= 10
return res
def DFS(array, i, j, threshold, visited):
if i<0 or j<0 or i>len(array)-1 or j>len(array[0])-1 or array[i][j]>threshold or visited[i][j]:
return 0
res = 1
visited[i][j] = 1
res += DFS(array, i+1, j, threshold, visited)
res += DFS(array, i-1, j, threshold, visited)
res += DFS(array, i, j+1, threshold, visited)
res += DFS(array, i, j-1, threshold, visited)
return res
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
array = []
for i in range(rows):
re