算法练习 - 分治

版权声明:本文为博主原创文章,未经博主允许不得转载。 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)

猜你喜欢

转载自blog.csdn.net/qq_28057541/article/details/71538252