版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28057541/article/details/71538252
算法练习 - 分治
练习1 LeetCode - 53. Maximum Subarray
递归式:T(n)=2*T(n/2)+O(n)
时间:O(nlgn)
java实现
public class Solution {
public int maxSubArray(int[] nums){
return maxSubArray(nums,0,nums.length-1);
}
// 递归部分
public int maxSubArray(int[] nums,int start,int end){
// 数组元素数量只有一个情况下,最大子数组就是这个元素
if (start == end){
return nums[start];
}
int mid = (end-start)/2+start;
int maxSumL = maxSubArray(nums,start,mid);
int maxSumR = maxSubArray(nums,mid+1,end);
int maxSumM = maxSubArrayMiddle(nums,mid,start,end);
return maxOfInterges(maxSumL,maxSumR,maxSumM);
}
// 时间复杂度为O(n),计算中间部分
private int maxSubArrayMiddle(int[] nums, int mid,int start,int end) {
int maxSumL = Integer.MIN_VALUE;
int sum = 0;
for (int i = mid; i >= start; i--) {
sum+=nums[i];
if (sum>maxSumL){
maxSumL = sum;
}
}
int maxSumR = Integer.MIN_VALUE;
sum = 0;
for (int i = mid+1; i <= end; i++) {
sum+=nums[i];
if (sum>maxSumR){
maxSumR = sum;
}
}
return maxSumL+maxSumR;
}
// Units
// 求若干个整型的最大值
private int maxOfInterges(int...ints){
int max = Integer.MIN_VALUE;
for (int i:ints){
if (i > max){
max = i;
}
}
return max;
}
}
练习二 LeetCode - 215. Kth Largest Element in an Array
原理:求一个数组的第k大数字问题,可以转换为求一个更小的数组的第k大数字问题。
这个更小的数组怎么求呢?很简单:
随机取数组中的一个值x,用类似二分的方法,将数组分为两个部分,ArrayLeft和ArrayRight。(有个划分的步骤)
ArrayLeft中数据都大于x,而ArrayRight中的数据都小于x。
这里分三种情况:
1. 如果ArrayLeft中元素数量等于k-1,那么返回x就是第k大的数
2. 如果ArrayLeft中的元素数量大于k-1,那么第k大的数就在数组ArrayLeft中,问题转化为,求ArrayLeft的第k大数字
3. 如果ArrayLeft中的元素数量小于k-1,那么第k大的数就在数组ArrayRight中,问题转化为,求ArrayRight的第(k-ArrayLeft.length)大的数字
注意:最终,使用了left和right两个指针来减少list的复制带来的内存开销,但是代码的可读和可理解难度陡增!
python实现
class Solution(object):
def partition(self,nums,left,right):
x = nums[left]
pos = left
for i in range(pos+1,right+1):
if nums[i] >= x:
pos+=1
temp = nums[i]
nums[i] = nums[pos]
nums[pos] = temp
return pos
def findKthLargestDivide(self,nums,k,left,right):
pos = self.partition(nums,left,right)
if pos+1-left > k:
# 第一种情况,大于等于nums[0]的数有pos+1个,而且比k多,那么第k大的数,就在这些数之中
return self.findKthLargestDivide(nums,k,left+1,pos)
elif pos+1-left < k:
# 第二种情况,大于等于nums[0]的数有pos+1个,但是比k少,那么第k大的数为另一部分的
k_ = k-pos-1+left
return self.findKthLargestDivide(nums,k_,pos+1,right)
elif pos+1-left == k:
# 第三种情况,大于等于nums[0]的数有刚好有pos+1 == k个,那么其中最小的nums[0]就是第k大
return nums[left]
def findKthLargest(self, nums, k):
return self.findKthLargestDivide(nums,k,0,len(nums)-1)
练习3 LeetCode - 241. Different Ways to Add Parentheses
参考了官网的算法,相关解释写在注释里了,这个算法还是用的很巧妙的
class Solution():
# 辅助函数,用于进行加减乘的计算
def helper(self,i,j,o):
if o == '+':
return i+j
elif o == '-':
return i-j
elif o == '*':
return i*j
# 递归函数
def diffWaysToCompute(self,input):
# 如果 字符串全部都数字,那么就是分治中的基本情况,返回字符串转数字的数组
if input.isdigit():
return [int(input)]
# 否则进入分解阶段
# 等式 = 子等式1 - 操作符 - 子等式2
# 等式中计算操作符的所有可能结果 = 子等式1的所有可能结果 进行对应操作 子等式2的所有可能结果
res = []
for i in range(len(input)):
# 在python2中 xrange 和 range 的用法是一样的,只不过xrange创建的是一个生成器,python3中,只有xrange这种实现,range实现被移除了
if input[i] in '*+-':
# 子等式1的所有结果
left = input[:i]
res_1 = self.diffWaysToCompute(left)
# 子等式2的所有结果
right = input[i+1:]
res_2 = self.diffWaysToCompute(right)
for r1 in res_1:
for r2 in res_2:
res.append(self.helper(r1,r2,input[i]))
return res
练习4 LeetCode - 240. Search a 2D Matrix II
对于本题而言,分治并不是最好,最快的解决方法,但是专项训练分治法的使用
c
class Solution():
def searchMatrix_Divide(self,matrix,target,bm,bn,em,en):
mm = int((bm+em)/2)
mn = int((bn+en)/2)
cur = matrix[mm][mn]
# 基本情况:当矩阵大小小于2*2的时候,直接遍历
if em-bm <= 2 and en-bn <= 2:
for i in range(bm,em+1):
for j in range(bn,en+1):
if matrix[i][j] == target:
return True
return False
# 递归情况:目标数比当前中间哨兵数值大,开始点后移动,否则结束点前移动
elif target > cur:
# 分别为 区域 2,3,4的搜索结果
res2 = self.searchMatrix_Divide(matrix,target,bm,mn+1,mm,en)
res3 = self.searchMatrix_Divide(matrix,target,mm+1,bn,em,mn)
res4 = self.searchMatrix_Divide(matrix,target,mm+1,mn+1,em,en)
return (res2 or res3 or res4)
elif target < cur:
# 分别为 区域 1,2,3的搜索结果
res1 = self.searchMatrix_Divide(matrix,target,bm,bn,mm,mn)
res2 = self.searchMatrix_Divide(matrix,target,bm,mn+1,mm,en)
res3 = self.searchMatrix_Divide(matrix,target,mm+1,bn,em,mn)
return ( res1 or res2 or res3)
else:
return True
# 暴力破解 O(n2),我的分治为O(n)
def searchMatrix(self,matrix,target):
# 基本情况:x小于matrix(m,n)
# m是行数
# n是列数
m = len(matrix)
# 排除空集的情况
if m == 0:
return False
n = len(matrix[0])
if n == 0:
return False
return self.searchMatrix_Divide(matrix,target,0,0,m-1,n-1)