1、什么是分治法?
分治法是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
2、分治法有什么特点?
分–将问题分解为规模更小的子问题;
治–将这些规模更小的子问题逐个击破;
合–将已解决的子问题合并,最终得出“母”问题的解;
3、力扣练习题
本题只是练习分治法,并不是该题的最优解
练习题:169、多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
代码:
public class Tem1 {
/**
*思路:先利用分治法中的分,将元素对半分,分到最后一个元素为止,计算该元素出现的次数,再用合的思想将一组组的各个元素个数计算出来,返回相同元素最多元素个数
*
* @param args
*/
public static void main(String[] args) {
int[] nums={3,2,3};
Tem1 tem1=new Tem1();
int element = tem1.majorityElement(nums);
System.out.println(element);
}
public int majorityElement(int[] nums) {
return maxSum(nums,0,nums.length-1);
}
public int maxSum(int[] nums,int left,int right){
//递归出口
if (left==right){
return nums[left];
}
//获取中间值
int mid=left+(right-left)/2;
//获取左边多数元素
int leftMax=maxSum(nums,left,mid);
//获取右边多数元素
int rightMax=maxSum(nums,mid+1,right);
//左边出现次数等于右边出现次数时
if (leftMax==rightMax){
return leftMax;
}
//左边出现次数不等于右边出现次数时,遍历元素,计算其出现的次数
//定义变量
int leftCount=0;
int rightCount=0;
//从左边到右边遍历,若为左边元素数最多时,左边元素加一,否则右边时,右边加一
for (int i = left; i < right; i++) {
if (i==leftMax){
leftCount++;
}
if (i==rightMax){
rightCount++;
}
}
if (leftCount>rightCount){
return leftMax;
}else {
return rightMax;
}
}
}
练习题:53、 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
代码:
public class Tem2 {
/**
*思路:分治法:将所求数组对半分解为一个一个小组,计算各组数之后就是,求各组之和的最大元素就是,再强各组最大相加,就是所求最大元素和
* @param args
*/
public static void main(String[] args) {
int[] nums={-2,1,-3,4,-1,2,1,-5,4};
Tem2 tem=new Tem2();
int maxSubArray = tem.maxSubArray(nums);
System.out.println(maxSubArray);
}
public int maxSubArray(int[] nums) {
return maxSubNum(nums,0,nums.length-1);
}
private int maxSubNum(int[] nums, int left, int right) {
//递归出口
if (left==right){
return nums[left];
}
//获取中间值
int mid=left+(right-left)/2;
//计算左边最大元素
int leftMax=maxSubNum(nums,left,mid);
//计算右边最大元素
int rightMax=maxSubNum(nums, mid+1, right);
//计算中间最大元素
int crossMax=getMaxCross(nums,left,right);
//返回左边右边和中间的最大元素
int max = Math.max(leftMax, rightMax);
return Math.max(crossMax,max);
}
private int getMaxCross(int[] nums, int left, int right) {
//获取数组元素中间值索引
int mid=left+(right-left)/2;
//计算中间值左边元素之和
int leftSum=nums[mid];
int leftMax=leftSum;
for (int i = mid-1; i >=left; i--) {
leftSum+=nums[i];
leftMax=Math.max(leftSum,leftMax);
}
//计算中间值后边元素之和
int rightSum=nums[mid+1];
int rightMax=rightSum;
for (int i = mid+2; i <=right ; i++) {
rightSum+=nums[i];
rightMax= Math.max(rightMax, rightSum);
}
//返回元素之和
return leftMax+rightMax;
}
}